Andrew Scott brought this one to my attention. It's what seems to be another example of Adobe finding the "too hard basket" being more convenient that rolling up one's sleeves and actually doing one's job properly.
Here's an issue relating to closures (and for once when that term is used, it actually is about closure in functions). 3495357 says:
When looking at the below code, the outer arguments have no scope, in Railo they use the variables scope which I believe is confusing, But it is also confusing to not have a scope as one is always taught that we should scope our variables.What Andrew is meaning is that the second helloWorld cannot be scoped. This won't work:
function helloTranslator(String helloWord){ return function(String name){ return "#helloWord#, #name#"; }; }
function helloTranslator(String helloWord){
return function(String name){
return "#arguments.helloWord#, #name#";
};
}
As CF will be looking in the argument's scope of the function expression not the outer function. Same with the local scope. So the only way of dealing with this is simply not using a scope.
Now this is not the end of the world, but the referencing of outer variables in the inner function is pretty bloody fundamental to the notion of closures (it's the actual "closure" bit... otherwise it's just a function).
Now the ColdFusion docs - "A closure can be used as a return type" - suggest that there's an owner scope, but that's not the case as far as I can tell. Their sample code errors:
Function function exampleClosure(arg1){
function exampleReturned(innerArg) {
return innerArg + owner.arg1;
}
/* return a reference to the inner function defined. */
return exampleReturned;
}
closure = exampleClosure(42);
writeOutput(closure(1138));
Element ARG1 is undefined in OWNER. | |
The error occurred inC:/Apps/Adobe/ColdFusion/10/cfusion/wwwroot/scribble/shared/git/blogExamples/closures/docs.cfm: line 4 | |
2 : Function function exampleClosure(arg1){ 3 : function exampleReturned(innerArg) { 4 : return innerArg + owner.arg1; |
But that would be the way to do it.
Basically what this means is that one cannot have variable with the same name - but obviously different scopes (in the memory-spacing sense of that term, not the usual CFML ones) - in closure code. Because the inner function "hides" the outer function's scopes. I suppose this is entirely reasonable except for the fact the way CFML generally works is that one can work around this sort of thing using scopes, eg: caller scope in a custom tag; local vs variables scopes in functions / CFCs, etc.
The Adobe response was "Closed/Deferred/NotWorthEffort". I think this is a bit poor, really. Obviously from the docs they intended to have the outer scope accessible, but it never made the cut (or something, dunno).
It's not as poor as other situations in which they've marked things as "not worth effort", but it does create a non-conformity in the language which doesn't exist elsewhere. Which is just annoying.
The easy work around here is to have a "transfer variable", which gives the variable in question a different name:
function helloTranslator(String helloWord) {
var outerArgs = arguments;
return function(String name) {
return "#outerArgs.helloWord#, #name#";
};
}
But having to do this sort of thing by hand is a bit lame. It's not so significant in these contrived examples, but I have run into this when the code is more complicated (possibly an indication I need to refactor my code, I know ;-).
Anyway, I said to Andrew I'd put my oar in on this one, and I think this should be dealt with properly, not simply swept under the carpet with a "aah [shrug]. Can't be bothered, really". Or at least there should be an explanation from Adobe as to why it's perhaps more of a problem that it might initially seem to be. It's disrespectful to close someone's ticket with "not worth effort", without actually advising them as to why. It just ends up seeming like laziness, whether it is or not.
--
Adam