Another ColdFusion 10 Closures Post

This post is more than 2 years old.

Edit on February 19, 2016: This blog post came up on a StackOverflow post today. The code I used in my sort was based on a beta of ColdFusion and will not work in the release or more recent versions. Specifically, my comparator must return 1, 0, or -1, instead of just true and false. See this answer which talks more about it and shows an example of how you can now do sorting on query objects directly.

Back in May I wrote a blog entry talking about how impressed I was with closures in ColdFusion 10. This was thanks to Mark Mandel introducing me to the awesome Sesame project. For the RIACon keynote I decided to share this and other examples.

I began with a simple example of how arraySort was updated to include closure support. Consider the following example.

I've got a simple static array of data I want to sort. I pass it to arraySort and dump the results.

Notice something? The bands that begin with "The" are sorted correctly, but not optimally. Instead, most folks would probably prefer them sorted by the letter after the word The. Using a closure, this becomes simple to fix.

I supplied a new function to arraySort that handles the comparison manually. If it finds that the string begins with "The", it just removes it. This could be a bit more intelligent, but you get the idea. Here's the result:

At the keynote, I talked about Mark's Sesame library, but also UnderScore.cfc by Ross Spivey. As you can probably guess, this is a port of the ultra-cool UnderScore.js library.

It has got quite a few features, but one that I thought was really cool was memoize. Memoize takes a function and creates a cacheable version of it. So given some method X, you can pass it to memoize to get some new function Y, that given input A will automatically cache all future calls with A as an attribute. Perhaps an example will make more sense.

You can see I've got a function that can be a bit slow. Essentially it gets slower as you pass it higher and higher numbers. But when I pass it to memoize, the result, in this case slowX, has automatic caching enabled. The first time I call slowX(4) it will be, well, slow. But the second time I run it will return instantly. My result from this script was:

Time diff after first call: 1602, diff after second call: 0

Finally - another person doing cool stuff with closures is Ben Nadel. He's written a few blog posts on it, but one in particular caught my attention. He wrote a UDF called reReplaceAll. It allows you to take a string, run a regex against it, and then fire a closure against every result. Normally you can't do much with replacements. You can do a bit of logic like upper or lowercasing results, but if you want to do something very complex with a match, you have to manually step through each result and update the string. With his UDF, you can simply do your complex stuff in a simple closure. Check out the example below:

I've taken input text, used a simple regex, and then written a closure that wraps each result in HTML while also reversing the actual match. Very simple and direct to use!

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Adam Cameron posted on 8/15/2012 at 3:11 AM

None of these examples are *closures*, Ray. They're just inline functions. True, inline functions are a handy feature of CF10 (and, I'd say, more handy than closures are), but you're not demonstrating closures here.

The whole thing about a closure - that which differentiates one from just a bog-standard function - is that it encloses variables from the context the function was defined in, rather than its variable references all being relative to when it's called. This is not happening in any of your examples.

closure != inline function

Uncharacteristically, the online docs offer a reasonable example of a closure:
http://help.adobe.com/en_US...

It's a good blog post, but it should be relabeled/retitled, I reckon.

Cheers.

--
Adam

Comment 2 by Mark Mandel posted on 8/15/2012 at 4:03 AM

C/P'ing from Wikipedia:
"In computer science, a closure (also lexical closure or function closure) is a function together with a referencing environment for the non-local variables of that function."

So technically all "inline functiond" in ColdFusion are actually closures, since they do include the reference to it's original environment.

I would attest that whether or not the code accesses variables from that reference is immaterial. The fact that it simply exists defines these code blocks as closures.

Comment 3 by Russ S. posted on 8/15/2012 at 6:37 AM

@Ray, thanks again for sharing Underscore.cfc. I'm very happy with how it has turned out, I only wish there were more contributors!

I'm going to be doing a BoltTalk with Tim Cunningham soon about my port of Backbone.js for CF, which is heavily reliant upon Underscore. http://cfmumbojumbo.com/cf/...

Comment 4 by Adam Cameron posted on 8/15/2012 at 10:22 AM

Hi Marc, fair enough: I'll concede the technical point there. *My* point was more than having this sort of example of closures is like having an example of Application.cfc and only talking about what a CFC is, without ever mentioning onApplicationStart / onRequestStart etc. And then saying "but it DOES demonstrate Application.cfc because it's a CFC and it's called Application.cfc".

Anyway, I guess I am kind of splitting hairs, and - like I said - I *do* think it's a good post as far as inline functions go. Just not so much as far as the "closureness" of closures go. If that makes sense.

I have an idea for an article on me own blog now though... ;-)

Cheers.

--
Adam

Comment 5 by Raymond Camden posted on 8/15/2012 at 2:16 PM

Just call me the instigator.

Comment 6 by Adam Cameron posted on 8/15/2012 at 2:28 PM

Ray, you Instigator you.

There: sorted.

;-)

Seriously... it might be a while before I get onto it, I've got a reasonable queue of stuff to write up. Also last time I checked for good closure examples, I struggled a bit. I note that the example in the CF docs is actually one I wrote by way of example (except "Maori" has been changed to "Hindi" ;-), so even Adobe didn't have many ideas.

But I'll find something. I enjoy the investigation.

Cheers.

--
Adam

Comment 7 by David Knighton posted on 8/15/2012 at 3:48 PM

+1 for Ace of Base alone!

Comment 8 by Salvatore Fusto posted on 8/16/2012 at 12:44 PM

imho the best way to demo a closure is a function returning a function; a pseudo code should be
function hello(title){
this.title=title
function hello2(name){
return name + title;
}
return hello2();
}
myfn = hello(" is the great!")
print myfn("Ray Camden") --> Ray camden is the great!
myfn = hello(" is fat!"(;
print hello("salvatore") --> Salvatore is fat!
seiously the hello fn returns a function and its own scope.
regards

Comment 9 by Adam Cameron posted on 8/18/2012 at 10:50 PM

@Salvatore, that's pretty much what they've got in the docs.

It's a good example for some docs, but I'm more interested in actual useful, real-world usage of closures (and the closureness of closures, not just that CF implements inline functions as closures. We get it. ;-)

--
Adam

Comment 10 by Salvatore Fusto posted on 8/20/2012 at 12:50 PM

Adam,
you are right, this is a simple doc-style example (derived from javascript code i've written not from cf), but it is usefull to describe how closure encapsulate a function and its own scope: calling the external function hello assign to myfn not only a value, but a scope too, see the variable title, that is passed to myfn and lives for all myfn's usages.
about usefullness of closuses and in line unnamed function, i try to explain my opinioon with an example: an algorithm is a set of rules applied to a set of data (think to a function to calculate the sun of an array element): without inline functions you have to write a function with 1 args (the array) so you have to a function for every action to perform on the array; with inline function you can separate data and action, writing a funzion with 2 args, a collection of data and a function representing action the action to perforìm on data: this way code becames more abstract and reusable (you can write a library of fn representing more action, sun, medium etc) to reuse.
more, closures let to avoid declaration and use of global variables.
of course, we can live without closure and unnamed fn, but imho the make our code more abstract.
regards.
ps: excuse my poor english, that can be responsable of misunderstanding

Comment 11 by Alexei Martchenko posted on 8/21/2012 at 1:31 AM

Who's Frank Sintra? :-)

Comment 12 by Raymond Camden posted on 8/21/2012 at 1:32 AM

The Punk Rock version! ;)

Comment 13 by Adam Cameron posted on 9/26/2012 at 11:23 PM

OK, "Mr Instigator", I finally got around to putting my money where my mouth is and doing my own blog article on this, over yonder: http://adamcameroncoldfusio...

Cheers for the inspiration and the instigation.

--
Adam

Comment 14 by Raymond Camden posted on 9/26/2012 at 11:41 PM

You and your silly methodical research. You know that doesn't below in the ColdFusion world! ;)

Comment 15 by Matt Bram posted on 1/6/2013 at 12:24 PM

Ray, Great Post! I was so happy to see that Adobe produced closures in CF10. This I believe in part, had more to do with the integration between ColdFusion and Microsoft OWS (Exchange 10) than anything else. I had developed a Java integration bridge using Microsoft's OWS JAPI with CF9. I had to do this entirely in Java because ColdFusion 9 does not do closures and I could not create the correct Interface in ColdFusion to work around, like the Java solution requires. With closures, we now get a huge benefit. I wouldn't be surprised to see our brethren/sisters developing messaging frameworks and all kinds of other kick you in the pants stuff for CF.

Great post :)
Matt

Comment 16 by Bill Tudor posted on 7/2/2015 at 2:31 PM

Ray I don't know if this s CF11 vCF10 thing but I couldn't get this to work until I replaced your gt test in the closured arraysort with compare()

Comment 17 (In reply to #16) by Raymond Camden posted on 7/2/2015 at 2:34 PM

Interesting. Well, upgrade to 11. ;)

Comment 18 (In reply to #17) by itisdesign posted on 11/16/2015 at 7:26 AM

Hi Ray,

I just ran into that too, but then checked the docs and see the comparator *must* return 1, 0, or -1.

Thanks!,
-Aaron

Comment 19 (In reply to #18) by Raymond Camden posted on 11/16/2015 at 11:57 AM

Ah cool, thank you for posting back.

Comment 20 (In reply to #19) by itisdesign posted on 11/16/2015 at 8:43 PM

Hi Ray,

You're very welcome!

Thanks!,
-Aaron