Thankfully for me (and anyone who is interested in using his closures package), Sean Corfield
reponded to my
Beauty of Closures post and set me straight on a couple of issues.
First, he confirmed that there was indeed a bug when attempting to use a mapping to use the closures, and that in fact, it wasn't a CF 6.1 issue only.
Next, he dove right into the code. So, for easy reference, here is my original code:
<!--- container.cfc --->
<cfcomponent>
<cfscript>
variables._arr = arrayNew(1
);
variables._curIndex = 0;
// adds an element to the container
function add(value)
{
_curIndex = _curIndex + 1;
_arr[_curIndex]=value;
}
// iterates over the container, letting a closure
// specify what to do at each iteration
function each(closure)
{
closure.name("run"
);
for (i=1; i lte _curIndex; i=i+1)
{
closure = closure.bind(value=_arr[i]);
closure.run();
}
}
</cfscript>
</cfcomponent>
His
each()
method is only slightly different from mine, but significantly so:
// iterates over the container, letting a closure
// specify what to do at each iteration
function each(closure)
{
for (i=1; i lte _curIndex; i=i+1)
{
closure.call(_arr[i]);
}
}
He mentions that I "[name] the method and then repeatedly [bind] the value variable. That doesn't actually do what he thinks." He's right. I was using it incorrectly, and I thought that it was sort of odd to do it like that. In particular, I didn't like having to name the closure. This syntax is much cleaner, and easier to understand. And the best part follows: I had mentioned that, "from my understanding of closures, you should be able to modify 'outer' variables within them. Thus, to be a 'true' closure, outputting
beenhere
above
should show true" in reference to this code:
<!--- closure_test.cfm --->
<cfscript>
cf = createObject("component"
,"org.corfield.closure.ClosureFactory"
);
container = createObject("component"
,"container"
);
container.add(10
);
container.add(20
);
container.add(30
);
beenhere = false;
c = cf.new("<cfset value = value + 3>
<cfoutput>
#value#</cfoutput>
<cfset beenhere = true>
"
);
container.each(c);
c = cf.new("<br/>
<cfoutput>
This container has the value #value# in it</cfoutput>
"
);
container.each(c);
</cfscript>
<cfoutput>
#beenhere# <!--- outputs false --->
</cfoutput>
Sean shows that in fact, had I used
bind()
as it was intended, outputting
beenhere
would have shown true, as expected. Basically, you can use
bind(outer=variables)
on the closure to get access to it. Then, in the code for the closure, you could use
outer.beenhere = true
and of course, the value is changed as you would expect. That is close to what I was thinking of when I said my idea would muck up the syntax, but I was thinking of passing it when creating the object. I actually like this a little better, as it is much cleaner than what I envisioned, and it is easier to see what's going on. It would be nice of course, if there was a way to do it without the programmer worrying about it, but I don't think that is possible with CF, since it uses the the same name for (from what I can tell) are two different scopes.
Anyway, thanks again to Sean for cleaning up my mess.
Hey! Why don't you make your life easier and subscribe to the full post
or short blurb RSS feed? I'm so confident you'll love my smelly pasta plate
wisdom that I'm offering a no-strings-attached, lifetime money back guarantee!
Leave a comment
There are no comments for this entry yet.
Leave a comment