Was surprised today that in Lucee, using cfloop qu...
# lucee
r
Was surprised today that in Lucee, using cfloop query overwrites variables inside closures nested in the function. To explain: inside
loopArray
there is a closure on
arr
, which outputs
id
. It was expected to cascade the
id
value from
loopArray
, but the variable from cfloop was output. Coldfusion outputs a variable from
loopArray
. In Lucee, I repeated it on versions 5 and 6 at https://trycf.com/. Is it bug or I expect something wrong?
Copy code
<cfscript>
qry = queryNew("id,name");
queryAddRow(qry);
querySetCell(qry,"id",1);
querySetCell(qry,"name","John");
queryAddRow(qry);
querySetCell(qry,"id",2);
querySetCell(qry,"name","Mary");

function loopArray(id) {
    var arr = [{
        "value": "100"
    }, {
        "value": "200"
    }];
    writeOutput("<br>id outside closure: " & id);
    arr.each(function(item){
        writeOutput("<br>id inside closure: " & id);
    });
}
cfloop (query=qry) {
    loopArray(id = 777);
};
</cfscript>
btw, if I use for/in insted of cfloop, I get correct (IMO) results:
Copy code
for(row in qry) {
    loopArray(id = 999);
}
Results for my first example (Lucee 5.4.3.2):
id outside closure: 777
id inside closure: 1
id inside closure: 1
id outside closure: 777
id inside closure: 2
id inside closure: 2
p
May be a bug but if you utilize this, it functions as I would expect it using the cfloop
Actually in your
arr.each
are you attempting to get the 100 and 200 values? because id is not defined in that
arr
r
I use
arr
only for make the closure example. The problem is that when I output "id" in function it's "777" (that value that I passed to function), but when I output "id" in nested closure it's "1" and "2" (value from cfloop). I expected value from parent function
p
But what "ID" are you expecting inside the loopArray and then within the closure?
Is it the id being passed in that you expect within the closure from the loopArray function args?
c
The results will depend on how Lucee is handling scopes for the variables & the context in which
cfloop
,
loopArray
, and
arr.each
closure. Here, it seems as if Lucee is runing the
arr.each
closure function in the context `cfloop`/`qry` rather than in the context of
loopArray
. If you specify
arguments.id
in
loopArray
(instead of just
id
), will you get
777
for all of your responses? If not, then I'd consider it a bug. If it does, question of whether it is proper functionality is still open. One could argue it should maintain compatibility with ACF. (edit: use of
arguments.id
throws error that
id
doesn't exist in arguments scope, maybe because of context it's running in)
r
@Patrick Yes, I expect cascading context and
id
from parent (
loopArray
)
@Cage S if we use arguments.id in closure, it means "arguments" for closure function, not for parent. I believe that
cfloop query
and
for/in query
should work same, but in for/in it works different.
a
I think the closure side of things is at least partially a red herring here. The same thing can be demonstrated with far less complexity in play: https://trycf.com/gist/ddc0204c2aa4c533f54b47c8d7bdb58c/lucee6-beta?theme=monokai
Copy code
<cfset qry = queryNew("id,name", "integer,varchar", [
    [1, "John"],
    [2, "Mary"]
])>
<cfset id = "outside query loop">
<cfoutput>Outside loop: #id#<br></cfoutput>


<cfloop query="qry">
    <cfset id = "inside query loop">
    <cfoutput>Inside loop: #id#<br></cfoutput><!--- 1,2 --->
</cfloop>
In a query loop... the first "scope" checked is the query reference. Whether or not it's in a closure should be neither here nor there. IMO Lucee's behaviour is correct here (the original). CF's is buggy.
Of course the enclosed
id
is completely shadowed by the query... it just means... don't use the same variable name in situations like this. Same as in any other situation this arises.
d
To me, ACF's behavior seems more expected. Since the query variable ("qry") isn't actually declared inside the loopArray function, I wouldn't expect to see it pick any localized variables from inside the loop. For example, if you change the example to change the query column name from "id" to "id2" and then add an local variable called "id" either inside the cfloop() or outside, it prints 777 for every line: https://www.trycf.com/gist/302aaac9651d5ce7286e3fa84b84fe5e/lucee5 So it definitely looks like there's some weird cascading going on with the scoping that doesn't look right to me.
💯 1
If you take the example I just posted and change the column name back to "id" from "id2", you get the original results. I'd file a bug for this.
r
@Adam Cameron But in
loopArray
when I use
id
it calls from arguments scope (writeOutput("<br>id outside closure: " & id)), not from cfloop. I expect that closure will check its arguments scope, after that parents arguments scope and after that cloop scope. Why Lucee checks arguments for function, but doesn't check it for closure?
💯 1
a
@dswitzer that's just because
id
(the arguments one) is not being shadowed by the same-named variable in the query any more. I did point that out. And this is entirely expected. I'm not sure what you are demonstrating with this. @romanstr good point! Despite that being clear in your code, I overlooked it due to being a div 😉. Yeah fair cop in that case. My "simplified" example is showing something different, missing that nuance.
c
Agree that Lucee should check arguments scope for closure but doesn't. Sounds like ACF does. And I imagine >80% of other languages would also. @romanstr Maybe worthwhile to post on dev.lucee.org and tag micstriit?
r
@Cage S I'll do it. Just wanted before to recheck myself and compare opinion with community 🙂
a
Don't tag Micha. If he wants to look at it, he will. I'd raise a ticket in Jira, and move on.
👍 1
d
@Adam Cameron To me, the query variables should not be hoisted up to the closure inside a function. It doesn't do this with vars in the variables scope. That's what my example illustrates. I would not expect the closure inside the function to have any knowledge of query scoped variable if it cannot see vars in the variables scope in the same way.
👍 2
c
Hehe, I'm sure he loves more work created for him 🙂 🙂
a
Being on the receiving end of random ppl tagging me for help on stuff, I am pretty bloody sure he doesn't.
💯 1
r