Adobe Solution Partner

February 5, 2007

The VAR keyword is idiotic

Filed under: ColdFusion — Tags: , — Steve Nelson @ 8:13 am

Macromedia (Not Adobe, I assume) screwed up with this one.

The var keyword needs to go away.

Think about this for a minute. When was the last time you wanted to NOT use the VAR keyword in a CFC? Reread that sentence. I’m not suggesting we want to not var our variables. I’m suggesting we ALWAYS want to var our variables. I’m suggesting we NEVER-NOT want to var our keywords (double-negative).

Sorry about that rant. In other words, I’m suggesting that setting variables inside of a cffunction should automatically be local variables, even if you do not use the var keyword. Right now they are automatically global variables. We already have a global scope, the request scope. We don’t need another one.

CFFUNCTION should treat unscoped variables as local variables. I.e. that variable ONLY exists inside the cffunction that created it. Similar to how variables are local in a cfmodule.

This is good syntax:

<cffunction name="myfunction">
    <cfset myvariable="hello world">
</cffunction>

This is bad syntax
<cffunction name="myfunction">
    <cfset var myvariable="hello world">
</cffunction>

IMO these two bits of code should do EXACTLY the same thing. Please Adobe, deprecate the var keyword, it is idiotic.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • LinkedIn
  • StumbleUpon
  • Technorati
  • TwitThis

30 Comments »

  1. I still have to admit that I don’t understand what you are talking about at all, John. The only getters and setters I’m familiar with in Java or C# are those written by developers.

    If you want a read-only value for a CFC instance variable, you make the setter private and the getter public. This is not complicated. You can’t make a variable private in the THIS scope because the THIS scope is public, just as it is in JavaScript. Still not understanding what the confusion is here.

    Comment by Brian Kotek — February 5, 2007 @ 12:00 am

  2. I agree that this is a pain at times and infact it’s extra coding, but would adding this feature require extra parsing from the cf engine? Surely there must be a reason why they require us to add the ‘var’ manually… isn’t there??

    Comment by Nick Tong — February 5, 2007 @ 12:00 am

  3. Hey Steve, first, I’ve heard this might be under consideration (either automatically or as a config option) in CF8. Remember, though, that this would break anyone’s code who is relying on the existing behavior. For better or worse, Adobe is very careful when breaking backward compatibility.

    Second, just to clarify, non-var scoped variables go into the variables scope of the containing CFC (they become instance data). So this is quite different than a "global" variable like the request scope. The two serve very different purposes. Just wanted to make sure other readers understand that!

    Comment by Brian Kotek — February 5, 2007 @ 12:00 am

  4. Brain (I prefer that name over Brian)-

    Yes it would break existing code if someone is making use of turning it off (not using it). That’s why I ask the question "do you ever want to NOT use it?"

    I’m not convinced anyone is NOT using it… on purpose. Plenty of people are not using it by accident. Like me. Whoops, I just found another one.

    Comment by Steve Nelson — February 5, 2007 @ 12:00 am

  5. Basically it would probably be anyone who wrote and deployed CFC code between 6.0 and the 6.1 release. I agree that there are probably not a lot of people, and further, in this case it might be worth it for Adobe to just say "tough luck people, on this one you have to change your code". I sure wouldn’t care if they did that.

    Comment by Brian Kotek — February 5, 2007 @ 12:00 am

  6. Am I wrong in thinking that the same thing can be done with the request scope?

    Comment by Steve Nelson — February 5, 2007 @ 12:00 am

  7. Maybe with a cfsetting or something. There should be a way to at least re-enable it for backwards compatability.

    Steve, easy on the double negatives. It’s confusing ;)

    Comment by erikv — February 5, 2007 @ 12:00 am

  8. Steve: no. The whole point of instance data for an object is that it is private and encapsulated within the object. This is where the methods come in: no external code manipulates the instance data of an object directly. They send messages (i.e. call methods) on the object to ask it to do something.

    Comment by Brian Kotek — February 5, 2007 @ 12:00 am

  9. My Dear Not Erik-

    Don’t stop ever not never not be not such a sissy-wussy-pants. If you can.

    Comment by Steve Nelson — February 5, 2007 @ 12:00 am

  10. I agree with what you say. I’m not sure if the functionality should be fixed for legacy reasons.

    My biggest problem is that the var keyword is inconsistent with the rest of the CF Language. There is nothing else like it in the language.

    I’m sure the CF team is cautious about making changes that affect how things work, though. I do not expect the var keyword to go away.

    My one addition to your request is that the "un-named function local" scope be given a name, perhaps "local".

    So this:

    <cffunction name="myfunction">
    <cfset local.myvariable="hello world">
    </cffunction>

    is the same as this:

    <cffunction name="myfunction">
    <cfset var myvariable="hello world">
    </cffunction>

    Then we ‘experienced developers’ could go back to blaming all the var scoping problems on people who do not properly scope their variables.

    Comment by Jeffry houser — February 5, 2007 @ 12:00 am

  11. Jeffrey, I disagree with the local scope idea. Well only kind of. The idea of adding a "local" scope is a fine solution, but it doesn’t solve the problem that already exists. There are countless (thousands? 10s of thousands? who knows?) ‘unvar’ed’ CFCs out there in the field right now that should be var’d and never will be. Adding a local scope requires the same amount of work as adding the var keyword.

    Plus… the "this" scope with all it’s flaws AND the "request" scope do everything that an "un-var’d" variable does. So there are basically 3 solutions (well sort of) to the same problem. An unscoped variable should be local to that function. A "this" scope variable should be global to the CFC itself, like it already is. A "request" scope variable should be global to then entire request.

    Comment by Steve Nelson — February 5, 2007 @ 12:00 am

  12. I don’t think it’s not a good idea for you to stop using double negatives is all.

    Comment by erikv — February 5, 2007 @ 12:00 am

  13. "An unscoped variable should be local to that function. A "this" scope variable should be global to the CFC itself, like it already is."

    Steve, this seems to miss one of the most crucial scopes: the variables scope of the CFC. This is private instance data and is critical to doing OO programming with CFCs. The THIS scope is public which nukes any chance of encapsulating the internal state of the CFC.

    Comment by Brian Kotek — February 5, 2007 @ 12:00 am

  14. Not that it helps the situation but here’s some historical background:

    In a .cfm file, foo = 42; is identical to variables.foo = 42; and thereafter references to foo are identical to variables.foo. And variables is the page scope.

    Since that’s so common to CFers, the thinking was that CFCs should work the same way. variables is the "page" scope – shared between functions in the CFC – and unqualified references use the variables scope.

    In particular, in CFMX 6.0, that was your *only* choice.

    In CFMX 6.1, a new function-local scope was introduced and, to preserve backward compatibility and the core axiom of foo == variables.foo above, a new declaration syntax was introduced, var.

    There’s a lot of code out there that does *not* use variables. as a qualifier for variables-scope names in CFCs and that code would break if you changed the lookup rule.

    Having said that, I agree that inside CFCs, we more usually want new variables to appear in function-local scope instead of variables-page scope and it would be nice to have an option somehow to change that default behavior. Either through a server setting (in CF Admin) or cfprocessingdirective or maybe as an attribute on cfcomponent and/or cffunction. The latter has the advantage of granularity so you could migrate code function-by-function to the new style although, technically, the cfprocessingdirective would be the "right" approach since this is a compile-time behavior change (and still allow you to change the behavior on a per-file basis to maintain compatibility with third-party CFC code).

    Comment by Sean Corfield — February 5, 2007 @ 12:00 am

  15. I’m not sure I follow Brian. I have a good understanding what the "this" scope does currently, but what is it doing incorrectly?

    BTW, I was goofing around with some code. I only see two situations where un-var’d variables really cause a problem.

    1) in an "init" method (well, any method that cfreturns "this")

    2) in a method that calls another method from the same CFC

    Those are the only two situations that I’ve come up with that var’ing seems to make any bit of difference. But Nat says he has some big horror story about un-var’d variables. I’m begging him to blog about it. Maybe we all say PLEASE.

    Comment by Steve Nelson — February 5, 2007 @ 12:00 am

  16. "I’m not sure i follow Brian. I have a good understanding what the "this" scope does currently, but what is it doing incorrectly?"

    The THIS scope is public, which means any external code can call <cfset myCFC.someThisScopeVar = "" /> and modify the internal state of the component directly, without going through a method. The entire point of encapsulating the internal state of a CFC is to hide the internal implementation of the CFC and force all client code (anything that uses the CFC) to go through a method call to have the CFC do anything. That includes modifying private variables.

    The whole reason no one uses the THIS scope is because it is public and lets any client code modify the CFC’s internal state directly. This blows away the whole point of making internal object data private and forcing client code to use the object’s API (its public methods). Make sense?

    Comment by Brian Kotek — February 5, 2007 @ 12:00 am

  17. Yes Brian. That shows that we need protected scope, public scope (or read/write control) of all this scopes. So far it seems to be something that is thought to not be possible. We need a hero to step forward on the crew and solve this for us and Adobe!

    Comment by John Farrar — February 5, 2007 @ 12:00 am

  18. Oh. I see. Yeah, that’s no good.

    Although that isn’t my reason for not using the THIS scope. I just haven’t come across why the THIS scope would make my code easier to read/understand. That’s my biggest concern.

    Comment by Steve Nelson — February 5, 2007 @ 12:00 am

  19. Not sure what you mean, John. We already have a public scope (THIS) and a private scope (VARIABLES) (which actually acts as protected since subclasses can see and modify these variables).

    Comment by Brian Kotek — February 5, 2007 @ 12:00 am

  20. You guys are forgetting in your fever of CFC talk that the <cffunction> tag can be used in a CFM page. As "function" can be used in the <cfscript> tag.

    God knows why one would want to have a function touch a "variables" variable. But it is possible. So with this in mind I do not think "VAR" will be taken away.

    Comment by Ian Sheridan — February 5, 2007 @ 12:00 am

  21. Although I am not a JS expert by no mean but I believe it uses a similar style i.e. you have to "var" scope variable within function.

    Brian, nice explanation about "this".

    Comment by Qasim Rasheed — February 5, 2007 @ 12:00 am

  22. LOL… I am talking about the standard idea of what an object is nearly everywhere but in CF. (And I like CF objects… and as much as I like CF would like to see a more standard object.)

    Standard concept: most languages provide getter/setter functions on objects. Can you tell me how to set a "read only" value for the "This" scope? No, of course not. You can in PHP, ASP, even in Flex! Yet, there are technical difficulties that prevent it in CF. In fact it would be great if when we set a value it called the setter automatically… WITHOUT calling a method when the "standard" for UML is setting or getting a value with the "attribute". (How are we supposed to use common UML tools to design CF objects when our public variables lack common read/read-only type functions?) … and I do like how PHP and Flex let you set a function to automatically handle the set function of a class attribute set.

    Comment by John Farrar — February 5, 2007 @ 12:00 am

  23. Simple solution.

    <cfset var local = structNew() />

    <cfset local.anotherVariable = ‘hello’ />
    <cfset local.anotherStuct = structNew() />

    etc, once you have the initial var, all local. vars are local.

    Comment by Dale Fraser — February 5, 2007 @ 12:00 am

  24. Yes but the point is you still have to explicitly var scope it when, ideally, any variable created within the method should be treated as local to the method. Unfortunately, aside from a configuration option where you say "yes I know that all non var-scoped variables will be method local" (cfprocessingdirective?) there’s no way to just globally apply this change to the langauge.

    Comment by Brian Kotek — February 5, 2007 @ 12:00 am

  25. Sure. Add an attribute to cfprocessingdirective, and add another scope ("CFC" or "Private") that acts like an un-var’d variable does now. Then fully deprecate it in CF 9 or 10. That would work for most of us.

    Comment by Steve Nelson — February 5, 2007 @ 12:00 am

  26. I think the VAR keyword is most excellent. I like the idea of being able to define something as temporary to that function and that function only. Personally, I do what Dale Fraser does with the var LOCAL scope and that works great.

    I also like to scope everything. That way, I can tell the difference between LOCAL scoped variables and ARGUMENTS scope variables that might have naming conflicts.

    To be honest, I think the best possible solution would be to make LOCAL a build in scope for all CFFunction scopes. Basically, build in the var LOCAL = StructNew() line of code. That way, you can still explicitly set something as being local, but no need to set up the scope.

    Not only does this save you a step, it make your code more understandable as it self-documents the availability of a variable.

    If we got rid of the VAR keyword, I suspect that it would be harder to tell where keywords were supposed to be available. Although I guess if you force the scoping of non-local variable, that would also help.

    Comment by Ben Nadel — February 6, 2007 @ 12:00 am

  27. You can also use the arguments scope as a "local" scope. As far as i can tell it’s thread safe and does not need to be declared in every function.

    Comment by Steve Nelson — February 6, 2007 @ 12:00 am

  28. Steve,

    Very true, and I have done that a bunch. The only time I can ever see that being a problem is when my arguments variable A and my local variable A have different meanings (in which case the two different scopes is needed). But again, that is a special case.

    When I do use the ARGUMENTS scope as a local scope, I tend to feel bad, like I am cheating, or misusing it… but I get over that and realize that ARGUMENTS is neither living nor does it have feelings :)

    Comment by Ben Nadel — February 6, 2007 @ 12:00 am

  29. Yeah i agree. It does feel like cheating.

    There also may be an issue with this during recursion. Specifically when overwriting an arguments scoped variable. Although I’m not 100% sure about this.

    Comment by Steve Nelson — February 6, 2007 @ 12:00 am

  30. I tried the test suite out and found as others have that using var was definitely the fastest. However I was curious what performance was like for the ‘var local = StructNew()’ and ‘use the ARGUMENTS scope as a local scope’ ideas. I enhanced the suite with tests for those, and found that they were quite a bit slower than using var, though still a smidge faster than using nothing. I’ll be choosing to use var then, as it’s no worse a discipline to develop than scoping everything.

    Comment by Darren Cook — October 17, 2007 @ 12:00 am

RSS feed for comments on this post. TrackBack URL

Leave a comment