Viewing By Entry / Main
December 21, 2005
Duck typing may be a new phrase to many ColdFusion developers but it is an established technique in several other dynamically typed languages (such as Smalltalk and Ruby). Hal Helms will be giving a talk on this topic at CFUNITED 2006.

What is it? It's a very flexible and powerful technique that allows functions to operate on any arbitrary component that implements the methods needed by that function.

Isn't that what interfaces are for? Well, interfaces (in other languages) can provide a specification of a set of methods that must be implemented by concrete classes. The (static) type system of those languages then only allows objects whose type explicitly implements the given interface to be passed into a function that specifies that interface as its argument type.

Duck typing allows any object to be passed into a function and, as long as the object provides the right method signatures, the function can use it. That means that it only has to implement methods that particular function actually calls and only needs to provide compatible function signatures.

For example, java.lang.Collection is an interface that specifies a lot of methods with very specific signatures. Suppose you had a function that just needs to call add() and remove() on an object passed in (that is assumed to behave like a collection). In the Java world your object would need to implement all of the methods in the collection interface if your function specified that as its argument type. That's a lot of work if your object is only collection-like rather than being an actual collection. Duck typing would allow you to specify the function could take any object and by documented convention only calls the add/remove methods on it. Then you could pass any object that implements those methods - even if it wasn't a full-blown collection.

It's a powerful technique and one that is more idiomatic for ColdFusion than extending the language to include full-blown interfaces. My Concurrency for CFMX library uses that technique for callable objects (release 1.0 had a Callable CFC base class that I deprecated in release 1.1).

In code, it's as simple as:

<cfargument name="someObj" type="any">
or:
<cfargument name="someObj" type="WEB-INF.cftags.component">

Comments

Now I agree in principle, but surely it'd be nice to have your CFARGUMENT tag specify "something" that was helpful in determining what you're looking for? The NAME attribute helps, but a specific type name in the TYPE attribute would be more helpful.

That's why I've stumped for tagging interfaces (i.e. Java-like interfaces with zero member methods) in CF. You'd rely on duck typing for the actual functionality, but you'd have a little bit of self documentation (and some runtime security) that you're at least passing around something reasonable.

So scrap the compile-time signature checks that interfaces typically imply, because they don't make any sense with CF, but leave the tagging benefits, and you've got something that could be really useful. As long as assigning types happens as dynamically as assigning methods, of course.


www.beust.com/weblog/archives/000269.html


Ah, Mike, I should have expected you to turn up and comment on this. Stick to Java, there's a good chap...


So basically there's no checking on the type of data a variable contains when it's passed into a method for use or does this only apply to passing a component reference into a method?


Michael, could you elaborate on exactly what you're asking?

If you say type="any", no checking at all is done. (I think that's the answer to what you're asking)


The bottom line is that it does not seem straightforward and clear, especially that statement above. Allows functions (meaning a CFC method?) to operate on any arbitrary component (passed CFC reference?) that implements the methods needed by that function. So the passed cfc reference will have functions/methods that the 'root' cfc will use? This implies to me that we're only working with passed CFC references rather than any passed data.


Well... if your method expects to be able to call toString() you can pass anything that supports that... which means you can pass pretty much any type of data (since a string or a number or a date supports toString()).

(But, yes, in general folks tend to mean CFCs as objects)

And, yes, methods can return an object or a non-object (but I would stick to just returning "" or an object to simulate 'null' and then use isObject() on the returned value). I don't think it's good practice to, say, return an error message or a live object - I think for errors, you should throw an exception...


I just posted something on blogoffusion that showcases my imperfect understanding. I'm really trying to see it as you do but it's not there yet.


Post Your Comments
Name:
Email Address:
Comments
*** Please note that all comments require moderation so it may be some time before your comment posts to this blog! ***
Remember My Information:
 



Hosting provided by