CF 9 local scope gotcha

I believe this behavior is as expected, however it can break code that worked in CF 8. Not so much break as in get errors, but you will get the wrong data, which is worse really. Similar issues have been discussed and maybe even raised on the bug tracker, but I didn't see an example quite like this, so I wanted to share.

Basically, when in a function and looping over a query or a list, you may reference a column name or the list index without adding a scope. For example, myQuery has a column named "key."

<cfloop query="arguments.myQuery">
<cfset local.key = key>
</cfloop>

On the first iteration through the loop, the variable local.key does not exist. The column "key" is found in the query, and now local.key equals that value; say it is 1. On the next loop iteration, CF sees that local.key indeed does exist and never looks to the query for the column "key." The scope hierarchy looks in LOCAL before it looks to the query we are looping over. So each subsequent assignment of local.key will equal 1.

There are several fairly simple workarounds: don't use the same variable name for the local scope; scope the right side of the assignment; etc. The point is you will need to watch out for this on legacy code.

See the enclosed file below ("Download Enclosure") for sample code.

4 Comments  |  Download Enclosure  ( 1 KB) |  CF General  |  Send
Posted 5/20/10 @ 5:19 AM by Matt Williams

Comments

@Matt,

This would be expected behavior, according to the code you've posted. You have not scoped the "key" you are applying to local.key. As such, CF does a scope check to find "key". Once the local scope is created it would be the first "key" located during the scope check (previously it would have looked at the variables scope first, so "local" would not have been an issue in CF8).

If you changed your set statement to the following it would handle the issue:

This is why it is so important to *always* scope your variables;)

Posted by Steve 'Cutter' Blades @ 5/20/10 6:54 AM

Formatting killed my example, so I'll try it again.

<cfset LOCAL.key = ARGUMENTS.myQuery.key />

Posted by Steve 'Cutter' Blades @ 5/20/10 6:55 AM

I agree Cutter. It is a code issue. I just want to make others aware that if you did not follow best practices (*gasp*), your code will potentially behave differently from CF 8 to 9.

Personally, I don't really like reassigning a variable to the same name in another temporary scope like this. I'd use tmpKey or something, though that can get messy too.

Posted by Matt W @ 5/20/10 7:22 AM

Like Cutter said, always, always, always scope all variables (even inside query output). I run into problems with unscoped variables on a daily basis and it drives me up the wall!

Here's the list of the CF 9 order of precedence for unscoped variables, I think they made some changes to it from version 8. http://help.adobe.com/en_US/ColdFusion/9.0/Developing/WSc3ff6d0ea77859461172e0811cbec09af4-7fdf.html

Posted by Eric Cobb @ 5/20/10 7:57 AM