For what it's worth this is how I solved the problem of not being able
to return a "null" CFC.
To reiterate the problem:
When a CFC method accepts or returns a datatype of CFC it's difficult to
do properly if the parameter is optional. If you set the return type to
the component type, for example you MUST return an object. However if
that property is optional the return type can't be set to the component
type as an error will be thrown. Also, the consumer of the data can't
assume that a component has been returned and must do a structural check
to determine the output (for example an "IsSimpleValue" or somesuch).
The bottom line is that this is handled by null in most languages. Null
can be passed as a value in method returns that would optionally return
object types. ColdFusion lacks the concept for nulls so a workaround
must be used.
My goal was to:
1) Allow methods that return component data types to ALWAYS return the
component datatype. I feel this eliminates the need for consumer
components/pages to "know too much" about the internal workings of the
component and allows the return type to be automatically protected by
the "returntype" attribute.
2) Make it easy to create and check for the existence of a "nullish"
return - in other words a way to make the return optional (but maintain
the proper return type) and still make it easy to determine.
3) Standardize (at least for myself) the process so that it works with
all components.
I'm not sure if my solution is unique or even "right" - but it does seem
to do the trick and (I think) it's fairly elegant. But I'd appreciate
any comments.
Anyway:
I began by writing a "root" component, named (oddly enough) root.cfc.
This component contains:
Note that upon creation a value "this.Null" is set to True. However
when the new() method is run it's set to False.
Also, I've attempted to solve the problem of locking component
operations by having this root class creates a unqiue "LockID" using a
UUID as a base. You can then use this value as the name of a lock to
serialize access to components.
I still haven't quite worked this last bit out... but the idea seems
sound. For example if you have a "collection" component that returns a
pointer to a structure of references you might name lock it (with this
name) to prevent another thread from running a "removeComponent()" on
the collection thus removing a component from the structure your
traversing.
Anyway - this root component is extended by all other components in the
package. A simple example called (again, oddly) "Sample.cfc" (sorry for
the lack of comments but I'm actually, surprisingly, trying to keep this
short):
This component takes a string "name" and "parent" that is of type
"Sample" (in other words Sample components can be contained in a tree of
parents and children). Not all Samples have parents, but some do.
Note also that Sample extends Root AND, in the new() method calls the
super.new() method (which as we saw sets the boolean value of
this.null).
The important thing is that the new() method will set the value of
"Parent" to a Sample component if one is passed. However if one is NOT
passed it will create a new Sample component (but it will NOT call the
new() method on it).
This means that you can easily determine if the Parent has a value (a
populated sample component) or "null". For example:
Sample "#mySample.getName()#"
has no parent.
has a parent and it's "#mySample.Parent.getName()#".
Sample "#myChildSample.getName()#"
has no parent.
has a parent and it's "#myChildSample.Parent.getName()#".
Note that you can just say "mySample.Parent.isNull()" (which always
returns a Boolean response) to determine the disposition of the parent.
Since the method isNull() is defined in the Root component it will work
for ANY component which extends it. The return is also ALWAYS of the
proper type.
The way I have it here is simplest, but you are potentially creating a
lot of "null" objects. You could also choose to create a single "null"
object of each type and reference that like mad if the total number of
instantiated components worries you. Although remember that a component
(especially before initialization via the new() method) takes up VERY
little space or resources.
You may also decide, if you like, to default the values of all
properties in the components upon creation. I didn't, but you could.
That's about it. Sorry this is so long, but I spent so long trying to
come up with a solution to this problem that worked for me I thought
others may be in the same boat.
I'd love to hear comments/criticisms on this.
Jim Davis
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
[
Todays Threads] [
This Message] [
Subscription] [
Fast Unsubscribe] [
User Settings]