Deciphering the new Local Scope
Recently it was announced that ColdFusion 9 will add a way to explicitly access the existing "var" scope inside functions, using a new scope named "local".
There has been some confusion, including on my own part, about exactly how it is implemented — so I thought I would do what I can to clear it up.
For starters, and as is always a top priority with ColdFusion upgrades, old code shouldn't break because of this change. While it is true that the following two lines are analagous, they are both still supported for the forseeable future:
<cfset var foo="bar"> <cfset local.foo="bar">
In addition, you will be able to create var/local-scoped variables anywhere in the method, not just at the top. Right off the bat, this is awesome and can cut down on quite a bit of typing. This:
<cfset var foo=""><!--- or: <cfset local.foo = "" /> ---> <cfquery name="foo">...</cfquery>
can become this, if you like:
<cfquery name="local.foo">...</cfquery>
How awesome is that? I'll tell you. Really awesome.
Now, on to some trickier things…
The "local" scope gives you explicit access to variables set in this scope. The scope has always been there; CF9 is just adding the local scope so that you can explicitly access it (read from it).
Previously, the only way to read variables from this scope was to imply that was where you wanted them from, by not including a scope name. ColdFusion would then infer that — since the variable exists in the unnamed local scope — that's what you wanted. To put it more explicitly, ColdFusion checks for the requested variable in several different scopes, and inside a method the unnamed local scope is at the top of that list. The first scope that contained a matching variable would be the value you got back. Now we'll have an explicit way to specify which scope to read from, including the previously-unnamed local scope.
Does this mean you don't have to var-scope any more?
Absolutely not.
But now you have two choices: Use the "var" keyword, or the local scope. As before, (and, I'm sure, partly to maintain backwards compatibility) if you neglect to include one of these indications that the variable is local, it will go into the object's global "variables" scope, which if not taken into proper consideration, is not thread-safe.
What happens to <cfset var local=structNew()/> ?
Without the ability to explicitly reference the unnamed local scope, the convention of creating a var-scoped structure named "local" was adopted as a community standard over years since the popularization of CFCs. As a result, you'll see a lot of existing code that has a var-scoped "local" structure.
If no special exceptions were made, then what you might end up with would be your custom "local" structure inside the local scope, something like the following:

Seems logical, right? Well that's not what happens. For whatever reason, in their infinite wisdom (and who am I to argue?), Adobe decided the better thing to do was to detect this case, and force the new structure into the object's global "variables" scope, so instead, this is what you end up with: Update: It just gets ignored, as Ben Forta's post states. (The confusion here was that at the time he wrote that, the beta didn't do what he said it would. It's since been fixed.)

… With one small exception, that I've found so far: If you execute a query and assign it to the local scope, like my 2nd code sample above (<cfquery name="local.foo">), for some odd reason, a key named "cfquery.executiontime" is added to the object's global variables scope:

For the most part, you can probably ignore that. But, on the off chance that you need it, now you know where to find it. Oh, and notice that it's got a period as part of the key name, so you can't use "variables.cfquery.executiontime" (well, ok, it might work, I didn't try…), but you would be better off using the syntax: foo = variables['cfquery.executiontime']; … and it's not thread-safe. So that's probably a bug, and will probably get fixed before release.
Scope precedence is still exactly the same as it was previously:
- Function local (UDFs and CFCs only)
- Thread local (inside threads only)
- Arguments
- Variables (local scope)
- Thread
- CGI
- Cffile
- URL
- Form
- Cookie
- Client
Server, Application, Session, Request, and Attributes scopes (still) require that they are explicitly named in order to read a variable from them. (Did I miss any?)
Posted in ColdFusion | Centaur | 16 Responses
In my interpretation, your example is trying to overload a scope.
Your implementation var local = StructNew() would be referenced as local.local.answer = 42. Typing local.answer to me is referencing the scope of local with a new variable of "answer" that is on the same variable peer level as local.local, which would have a key of answer as member of local.local.
I hope that translates of my intent.
As per Ben Forta's post on his <cfset var local = {} /> will be ignored in CF9, it wont creat local.local .
This wont be an issue as the local scope exists so <cfset local.name = "Paul" /> is valid as local is there waiting. It may only potentially be an issue if you have <cfset local = "Some local string or data" /> as this would be ignored in CF9.
http://forta.com/blog/index.cfm/2009/6/21/The-New-ColdFusion-LOCAL-Scope
<cfset variables = "Hello" />
<cfset variables.message = "Hello">
The first statement creates variables.variables and the second obviously creates variables.message.
I find it curious they are making an exception for "local" to act differently, unless they plan to do this with other scopes as well.
I do not see an issue with creating local.local as it is just a poor variable name choice and not necessarily a implementation failure.
local.local
... not variables.local.
Is ignored in CF9 and it is documented. Asha also mentioned this on Ben Forta's blog.
Was this functionality that was changed in the last 3 weeks? Or was Ben Forta misinformed at the time of his blog post? I only ask because I've seen the local.local thing a number of times.
Sounds cool. I can't wait for the public beta!! :D
Coding for a poorly named variable (as in naming your variable after the scope you put it in) versus consistency of the language to create variables implicitly.
It is good conversation fodder, but at the end of the day it would not matter much as more formal coding practices would probably avoid this nuance.
I know what the new local is for and what it solves. I know the benefit of being able to declare local scoped variables at any point of a member function.
What I seem not to be able to convey is if CF9 ignored <cfset var local = {} />, this would go against consistency of being to create a local variable named local. Other scopes in current functionality allow for this. As I caveatted, I find it a bad naming convention, but again that is besides the point.
I was inferring any inference to wanting to overload the local scope or that was the intention of the code on this blog.
I was just commenting that now in a special scope now has a special condition that does not act like other scopes now when declaring variables.
I will throw in the towel here and accept this a moot argument and as I said in my previous post, "it is good conversation fodder". Nothing more, nothing less.
Cheers and I look forward, like Ben, to the open beta.
"I was not inferring to wanting to overload the local scope or that was the implied intention of the code on this blog post."
<cfset local.local = "Some data" />
As local as a struct exists implicitly and is private to the method. Personally I am in favor of this as we always use: <cfset var local = {} /> so we don't need to var scope multiple variables.
From a consistency standpoint, I would agree with you; but that said, I think we have to make an exception because they're doing this in order to address an issue from previous versions. I'm not exactly sure what sort of issues might arise if they didn't ignore it, but one thing I *am* certain of is that they have spent many more hours (and dollars) considering the problem than I have; so I trust their judgment.
Nothing to apologize over. Tonality of voice is ahrd to translate in text.
I have to trust in their decision as I do not have a say in the matter, so to speak. I can make asides, but they are just that.
Cheers and happy coding