Home > ColdFusion, Javascript > Be careful with the ‘local’ scope when migrating from CF8 to CF9

Be careful with the ‘local’ scope when migrating from CF8 to CF9

One of the really nice “fixes” included in ColdFusion 9 from a developer’s perspective is the inclusion of an implicit “local” variable scope into which variables created within the body of a <cffunction> tag are placed by default. Previously, developers had to manually add a “var” keyword to variables that should only exist within the confines of the function.

One of the ways of simplifying this that gained some traction among various developers prior to the release of ColdFusion 9 was to “var” a single variable at the top of the function as an empty structure then store any additional variables needed in the function inside it. Many folks, myself included, named this structure “local” so that it would be readily apparent that the values inside were local to that function. This approach worked fine and dandy on ColdFusion 8 and below.

I recently migrated one of my clients to ColdFusion 9 and not long after the client started getting isolated reports from his people having javascript errors in a data management application that uses AJAX-driven forms talking to CFCs. At first these were very isolated and we weren’t able to reproduce the error, but, as time went on, the reports became more widespread. As I was troubleshooting this over the weekend, I discovered that we were getting javascript errors when trying to interact with this RemoteFacade CFC about 40% of the time.

Using Firebug, I was able to watch the results come back from ColdFusion and noticed a very odd trend. Approximately 60% of the time, the JSON returned from the remote CFC call was as expected. In the other 40%, one of the main data structure names was an arbitrary, machine-generated name instead of the name we had specified in the code.

Here is an example of what we were expecting in the JSON returned from the RemoteFacade.cfc method:

{"DATA":{"CANEDIT":true,"RECORDDATA":{"Field1":"value1"} } }

This is an example of what we would get back from the same request when we would see the javascript errors

{"___IMPLICITARRYSTRUCTVAR5":{"CANEDIT":true,"RECORDDATA":{"Field1":"value1"} } }

See the difference? Our “DATA” key was named completely differently which caused javascript to throw some error saying that variableName.DATA did not exist.

After looking over the ColdFusion code for quite a while and doing some step debugging with FusionDebug I had an idea. I changed all the function-specific structures I had been using from:

<cfset var local = structNew() />
   ....
<cfreturn local />

to:

<cfset var ret = structNew() />
   ....
<cfreturn ret />

Once I changed those throughout the code base and reinitialized my application, all the javascript errors that we’d been experiencing across multiple request types went completely away.

I have an unconfirmed theory that in using the name “local” for my structure, ColdFusion was sometimes getting “confused” on what to return–ColdFusion’s built-in local scope or the method-specific variable I had named local. I don’t really have any way to prove that beyond a shadow of a doubt, but when I made the change, all my errors went away, so I decided chalk it up as a lesson learned for future development and move on to the next problem. Needless to say the client was happy that the issue was fixed and I can say I learned something that day.

Categories: ColdFusion, Javascript Tags:
  1. February 8th, 2010 at 10:07 | #1

    Dan, off the top of my head I think if you code had the variable local set it would then set it as local.local. I remember some talk of this around the public beta.

    Mr Forta has info on it here: http://forta.com/blog/index.cfm/2009/6/21/The-New-ColdFusion-LOCAL-Scope

    “It’s clean, it’s simple, it’s intuitive, and it’s fully backwards compatible. And yes, if you have a variable named “local” it’ll still work, the variable will just become LOCAL.local, and as the LOCAL scope is in the default evaluation chain it’ll just work.”

  2. February 8th, 2010 at 11:07 | #2

    @Kev Yeah, that’s what I thought too. But I would have thought it would have failed every time that way, rather than the roughly 60/40 split I was seeing. The good news is that the fix worked, the bad news is that my testing regimen for moving sites from CF8 to CF9 is going to need updating.

  3. Michael Horne
    February 8th, 2010 at 11:11 | #3

    I was beginning to think it was just me! Totally unable to describe the error!

    I’ve found another ‘gotcha’:
    If you use CFTHREAD and within that tag you have references to the local scope (this includes functions called within the thread), the LOCAL scope is destroyed. You can literally have:

    #local.wibble#

    and under certain circumstances, wibble will be undefined in local!

    Again, I’ve been searching for this error online but no-one else seems to have it.

    It appears the local scope isn’t quite as safe as it seemed.

  4. February 8th, 2010 at 20:57 | #4

    I may misunderstand what you’re saying, but I don’t believe the new ‘Local’ scope is implicit, nor are variables placed there by default. The default scope is still the Variables scope. To make a variable part of the Local scope, you either have to ‘var’ it or explicitly place it in the local scope (local.myVar = 123).

  5. February 9th, 2010 at 00:59 | #5

    @lachdav You are correct, the variables you define are not put into the new local scope automatically unless you use the VAR keyword or assign them to local.x. Ray Camden wrote this post covering that very thing earlier today. However since my code was doing <cfset var local = structNew() /> that should have created a Local.local structure. My return statement in those functions merely said cfreturn local which should have returned the entire local scope, not just my individual structure. The fact that it was sometimes returning the structure named differently was the key to the problem I was having. Once I changed from using “local” as my variable name to using “ret” the ambiguity went away and the application started working correctly again.

  6. February 15th, 2010 at 12:21 | #6

    Michael,

    From what I heard from Rupesh Kumar, CFThread runs as a function call, so it might be getting confused between the two local scopes (the one inside the CFThread and the one inside the CFFunction). I’ll have to do some testing on that.

  7. March 4th, 2010 at 12:34 | #7

    What you probably do not realise as well is that using “local” to scope your variables also has other issues that exist prior to CF9.
    If you store a query in the scope, e.g.

    Then you can have problems working with this query while it is in this scope. It took me quite some time to work out why my queries were going screwy, but as a result I had to change all my scoping to LOCALS instead of LOCAL to resolve the problem.
    I do not recall what the exact problem was as it was a couple of years ago, so wa son CF6 or 7.

  8. Joe Hayes
    April 6th, 2010 at 12:02 | #8

    See this post:
    http://www.bytestopshere.com/post.cfm/major-flaw-in-cf9-may-break-code

    …and the corresponding bug report:
    http://cfbugs.adobe.com/cfbugreport/flexbugui/cfbugtracker/main.html#bugId=80621

    Should be fixed under hotfix 1, but I haven’t verified (see bug 80621):
    http://kb2.adobe.com/cps/825/cpsid_82536.html

  9. April 6th, 2010 at 14:42 | #9

    I too have been in the habit for years of using at the top of each function and pass almost everything around in this structure within each function, then pass that structure – or portion of that structure – out as a result.

    In the process of upgrading a development box to CF9 (preparing to move the production machines to CF9) I found that some references to complex data types (nested structs, or a query in a struct) can no longer be referenced reliably ie: “local.query.recordCount” in CF9… this stinks. And it’s one of those “sometimes it works, sometimes it breaks” kind of bugs.

    Changing the name of the “var-previously-known-as-local” to something else (like “result” or “my”) in the cfset fixes the problem. (Both are poor names to replace “local”)

    BTW – I’ve applied the Hot Fix 1, still had the same problem until I renamed my “var’d variable”.

    Now I just have to decide what is a suitable variable name to replace “local”, and fire up trusty old Dreamweaver to do a mass search and (delicate) replace…

  1. No trackbacks yet.
*