You can download my Closures for CFMX library from the "Software" pod on my blog.
Read the comments in the index.cfm file for details on how to use it. Here's one example from that file:
<p>doubler.call(n=21) = #doubler.call(n=21)#</p>
<cfset calc = cf.new("multiplier * n","n") />
<cfset calc.name("do") />
<cfset triple = calc.bind(multiplier=3) />
<p>triple.do(14) = #triple.do(14)#</p>
You'll get 42 each time. No idea what anyone might want to use this for but it's "cool". Enjoy!
Peter Bell added a few comments including a link to Martin Fowler talking about closures. I figured I'd add an example showing how you might do similar things in ColdFusion with this library.
First off, you need a select function to match Ruby:
function select(collection,closure) {
var result = structNew();
var e = 0;
for (e in collection) {
if (closure.call(collection[e])) {
result[e] = collection[e];
}
}
return result;
}
</cfscript>
Now we'll build a collection (a struct) containing some simple struct data elements:
<cfset e = structNew() />
<cfset e.name = "Sean" />
<cfset e.isManager = true />
<cfset emps[e.name] = e />
<cfset e = structNew() />
<cfset e.name = "Matias" />
<cfset e.isManager = false />
<cfset emps[e.name] = e />
<cfset e = structNew() />
<cfset e.name = "Paul" />
<cfset e.isManager = false />
<cfset emps[e.name] = e />
What for, other than cool? Maybe Peter Bell can use this for his application generation framework. ;)
JUST TEASING PETER! :D
J
@Jared - NP at all! I've been reading up on closures on and off for weeks now. Now at least I have some sample CF code so if I can just think of something to use this for I'll be set!
Truth be told, I still don't really "get" closures, but I have a book on Haskell with my name on it and I'm reading a lot of Ruby code, so I'll be sure to let you know if I figure out what this could be used for.
Like Mixins, I'm sure there's gold in tham thar patterns . . .
@everyone - if anyone thinks up some interesting use cases for closures in CF I'd love to hear them!
The Ruby examples Fowler gives assume collections of objects and a select function. Select takes a closure and returns the elements of the collection for which applying the closure's method returns true.
I'll edit my entry to show how that might work in ColdFusion with this closure library.
function select(collection, closure) { var result = structNew(); var e = ""; for (e in collection) { if (closure(collection[e])) { result[e] = collection[e]; } } return result; } function test(e) { return e.isManager; }
select(emps, test);
The only thing missing is the function literal in the call to select (you have to predefine it). If CF would just support functions as a "real" datatype (including a literal syntax), then you'd have it all, without any extra weirdness.
Of course, you'd want the scoping rules of a closure as well, but I assume that your CFC's don't provide that? It would be remarkably inefficient to do so, I'd think.
cf.new("return e.empStatus = statValue;","e").bind(statValue=x)
That creates a closure with statValue bound to the local x variable in the calling code...
Which isn't to say this isn't useful, of course, just that there are some gotchas to be aware of.
Currently, when you bind a value type, the closure keeps that value (even if the variable is subsequently changed); when you bind a reference type, the closure keeps the reference but picks up live changes. Also, the closure itself has "history" in that changes to bound variables inside the closure affect future calls to the same closure instance (this is actually useful since you can write an aggregator with a closure).
That may indeed cause surprises. I considered machinery to perform a deep copy of bound variables but decided it was too much overhead for a proof of concept.
I'll be interested to see what sort of feedback people have once they start trying to use this in the wild...
Could you suggest some starting points (as with mixins which now make all the sense in the world to me) for experimentation?
If you're building a cms, writing a DAO or service or controller, creating a shopping cart or write a newsletter system where is a time that a closure would help you to solve a problem more flexibly or elegantly than just having methods within a class.
About the only thing that has penetrated for me is that you can dynamically create a function that has certain cool properties in terms of its existance and relationship to or access to the caller scope or something. Any thoughts appreciated, but more importantly, I'm voting for this to be a project if you have the time and will definitely take the time to learn enough about closures to take advantage of anything you create!
That way it could be very easy to filter out objects from a group, or resort them in a custom way that Transfer doesn't automatically handle internally.
I'd have to look through my old ColdFusion code to see if I can come up with some examples that would be made simpler by the use of closures.
Mark may be on the ball with using closures to create reusable ad hoc queries... definitely a way to create filters etc on the fly.
ANY new pattern requires a learning curve on the part of other developers reading your code. Think of how hard it is for a procedural CF developer to make sense of a well architected application using CFCs. Does that mean CFC's are wrong?!
The question is whether the additional learning pays for itself by allowing you to solve problems more elegantly. For en example, look at my LightWire code as a good example of Object based mixins. You have an entire DI/IoC engine including the resolution of circular dependencies in under 200 lines of code (including a couple of required base methods). In many ways it is an inferior approach when compared to ColdSpring, but ColdSpring is a little more than 200 lines of code! Using object based mixins allows DI to be simplified to the point where anyone can "get it" and indeed anyone can just "write it themselves" if they have a good reason to.
Mixins can be confusing when you first see them, but they may repay the study if you have the kind of problem they can be used for (despite all of the usual caveats about losing the self documenting nature of the class files).
I'm pretty sure closures are the same and am interested in Marks ideas above and to hear if anything concrete comes to Sean.
@Peter: I'm not against learning something new, if someone can make the case it is worthwhile (CFCs over UDF for instance). I'm not seeing closures as offering anything. Maybe as Sean said it was a bad example.
Glad to hear you got it working.


