Calendar
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
Recent Entries No recent entries.
Recent Comments
Flex: Making Scrollbars Follow Focus
Daryl Banttari said: Still works fine for me. As I tab from field to field, the scrollbar adjusts to ensure the field wi...
[more]
Flex: Making Scrollbars Follow Focus
newchild said: your autoscroll class doesent scroll automaticly, even in your example. So what exactly is that for?...
[more]
Reviving the Lost Craft of Writing Specification Documents
Tanya said: Thank you:)
[more]
ColdFusion SQL Injection
Sam Singer said: Will this run on os x?
[more]
Reviving the Lost Craft of Writing Specification Documents
Nat Papovich said: Hi Greg, yes that was intentional. It's just an example, after all :)
Tanya, take a look at the Pow...
[more]
Archives By Subject
Business of Software (5) [RSS]
ColdFusion (321) [RSS]
Conferences (7) [RSS]
Databases (88) [RSS]
Flex & Flash (109) [RSS]
Fusebox (87) [RSS]
General Development (33) [RSS]
Google (9) [RSS]
Hardware (5) [RSS]
JVM & Java (132) [RSS]
Linux (20) [RSS]
Macintosh (1) [RSS]
Miscellaneous (254) [RSS]
Performance (8) [RSS]
SeeFusion (36) [RSS]
Shan's Simple Examples (7) [RSS]
User Interface (3) [RSS]
Windows (5) [RSS]
Archives By Poster
Daryl Banttari (11)
Nat Papovich (33)
Patrick Quinn (36)
Shannon Hicks (22)
Steve Nelson (22)
Tyson Vanek (3)
Why you need to VAR-scope your variables
Yes, the use of the var scope is idiotic. I haven't met a developer yet (in person) who thinks that Macromedia did it "right" with that keyword. But Steve's opinion that you don't need it because a CFC only needs two scopes isn't fully fleshed-out, I think.
By default, the attributes that a VAR'ed variable acquire should come naturally to all variables defined in a method body either A) without a scope or B) in the variables scope. That is, the variables scope should be local to the method body.
So we all agree we need a method-local variables scope and we don't want the hassle of defining and var-"scoping" them like we have to do now. But we also need a CFC scope, visible across the entire CFC. Right now, the variables (unscoped) scope does that. You set a variable in a method with no scoping and no "var" keyword and it's available in any other method. Very handy for instance variables.
So, we need a method-local scope without a goofy syntactic-exception-case "var" keyword, and we need a cross-method scope like the current "variables" scope in a CFC. The "this" scope is already botched. Adobe can't change the behavior of it without hosing thousands of developers who rely on it. (Yes, you OO purists, it's okay to use that scope. We're not writing Java apps here.)
Adobe can't modify the behavior of the variables scope since nearly everyone I know uses it in their CFCs for CFC-wide variables, mostly of the "instance" variety.
So what are the language experts to do? Formalize the init() method of a CFC to expose any variables defined there as CFC-wide variables while restricting undefined variables in other method bodies with the var-scope behavior? That wouldn't work because we have many instances of code that uses these features.
The bottom line is that Adobe cannot change the behavior of the scoping and "var" keyword without breaking thousands of developers' code. Nearly everyone knows the implications of not VAR-ing your variables and knows how to apply variables across a CFC.
The problem is that we're lazy. ColdFusion doesn't make us declare variables ANYWHERE ELSE. Yes, Macromedia messed up pretty bad, but the mess is made, and we've all adapted to the mess. We'll just have to keep it up for all eternity.


Granted, we're talking to a very small audience, but I have not heard a single person say "hey wait I use un-var'd variables ALL THE TIME! And i do it on purpose".
I'm not sure what you're asking for isn't already there. the THIS scope does exactly what you're talking about. Set a variable in the THIS scope and it available to the other methods (assuming you return this and update the object instance). Even though it offers the added feature of being publically editable, which Brian pointed out as a bad idea, that doesn't mean it won't do what you're asking for.
Why can't you do what you're talking about with the THIS scope?
btw, i meant: <cfset> in the last post.
The THIS scope and the VARIABLES scope are exactly the same, except that THIS is public and VARIABLES is private. Which is why using the THIS scope is not an option.
As to why, here is my horror story:
I had the following code in an Application-scoped component (never mind why I was looping through a list this way, it worked well in my situation).
<cfscript>
var mylist = arguments.items;
for ( i = 1; i LTE ListLen(mylist); i=i+1 ) {
item = ListGetAt(mylist,i);
//other code that uses "i" and "item"
}
</cfscript>
I tested it and it worked fine ("mylist" can be set with or without var for this example, it doesn't matter).
Then, days later I get an error on this line:
item = ListGetAt(mylist,i)
The error says that "i" is higher than the number of items in the list. No way that is possible, right?
Wrong.
The code was executing at roughly the same time for two different requests. "i" was getting set as a CFC-level variable on each loop. So, the value of "i" in one run got set by the loop in another.
That is why "var" is essential.
If not, how would one i value from one user affect another user, regardless of the var'ing? It almost seems like an underlying CF error that goes beyond the var keyword itself.
in some component:
<cfcomponent>
....
<cffunction name=somemethod>
<cfset somevariable="hello world">
</cffunction>
</cfcomponent>
then:
<cfinvoke method=somemethod component=somecomponent>
<cfoutput>#somevariable#</cfoutput>
Is that what you mean? You WANT to do that? Are you serious? Please tell me you're kidding. Please tell me I misunderstood. Please tell me it's a cruel joke. Please!
<cfcomponent>
....
<cffunction name=somemethod>
<cfset somevariable="hello world">
</cffunction>
</cfcomponent>
Will end up creating a variable named variables.someVariable within the CFC. This is a PRIVATE variable, nothing outside the CFC can access it. It's the same as doing this:
<cfcomponent>
....
<cffunction name=somemethod>
<cfset variables.somevariable="hello world">
</cffunction>
</cfcomponent>
Now if both requests were updating an application scope variable that was somehow unlocked, I could see this occurring. But you're saying that's not the case. Does this happen with a simple cfset statement? Is that all it takes?
request scope: exists in the calling cfm pages and ALL cfc methods
this scope: exists in the calling cfm template with the prefix of the name of object instance. i.e. <cfset myobject=createobject(....)> then: #myobject.somevariable# Then inside the cfc it is: #this.somevariable#
variables scope or no scope: when no cfcs are used (cfm only) it is available across all included cfm files. When set inside of a cfc it is available across all methods. Not available outside cfc.
var'd variables scope or var'd no scope: available only to the immediate method.
My opinion... get rid of var scope, make un-var'd variables/no scope variables local to individual methods the way a var'd variable is right now. Then add another scope "local" or "cfc" that acts like an un-var'd variables/no scope does right now.
Brian, is that right?
This code works:
<cfscript>
var mylist = arguments.items;
var i = 0;
for ( i = 1; i LTE ListLen(mylist); i=i+1 ) {
item = ListGetAt(mylist,i);
//other code that uses "i" and "item"
}
</cfscript>
The reason is that if i is set with a "var" keyword, it is stored in the variables scope of the component (private variables that persist across the component).
Because the component is stored in Application scope, all variables-scoped variables in the component are effectively Application-scoped variables.
So, effectively, you are right that an Application-scoped variable is in play. This isn't a memory leak and it isn't poor thinking on Macromedia's part.
In my data access components, I can use "variables.datasource" to store the datasource. If that didn't persist with the component, then I would only be able to use that variable during the request in which the variable was created - which would be of little use.
Using "var" fixes that for the exact same reason that it you should use it in UDFs - it makes the variable a function-scope variable. That is to say that the variable only exists within the function call that created it. It isn't just local to the function (in the way variables is local to the CFC), it is local to that run of the function.
http://ray.camdenfamily.com/downloads/cfcscopes.pd...
One aspect that has so far escape specific coverage is exactly what you mention - the bogus "initialization". Can we all agree that the var keyword must remain, but the bogus initialization need not remain?
Welcome to the 21st century, Nelzian. Your lack of understanding of elementary CompSci and OO principles is truly astounding, even by Armenian standards. ;)
I want local variables.
I want global variables.
I simply want the language to deal with these variables in a consistent, clean way. In ColdFusion we have scopes. The "var" keyword is NOT a scope, but it acts like a scope. It is UN-ColdFusion. It needs to go away and be replaced with something that IS consistent with the ColdFusion language.
IMO, the variables scope and the un-scoped-scope was already defined as a "local" scope in a cfmodule. That scope concept should, IMO, transfer to cffunction as the local scope.
That would be like saying application scopes work differently in cfcs than they do in cfms. It just doesnt make any sense.
Will this happen overnight? Of course not. Until then we have to make sure everything is in fact var'd. It means we ALL need to use tools like Mike Schierberl's VarScoper http://www.schierberl.com/varScoper/
I was under the impression that unscoped variables were private to the method but not to the instance of the method. For example, I thought the problem was that if two requests hit the same method in the same persistently scoped cfc instance, there could be problems with race conditions. However, I didn't think that there could be a conflict with two different methods using the same unscoped variables name.
I've been using unscoped variables in methods for constants, values that are set once. However if they are in fact variables scoped then there is a chance I will hit some kind of bug following this misguided, though admittedly infrequent, practice.
ARGGG
...and not in the fun pirate way
...more like in the depressed pirate way
<cfset var CFHTTP = "">
<cfhttp ....>
While I don't mind the var keyword generally, I do find this an annoyance. It's not the end of the world though.
You wrote:
"See i think they can modify the var keyword without breaking everyone's code. If they basically deprecated the var keyword so it did nothing i.e.: <cfset var myvariable="hello world"> is the EXACT same thing as <cfset myvariable="hello world"> how many apps would that actually break? I'd be willing to bet it would break exactly zero."
Actually, ever single CFC I've ever written would break.
You see I use the "instance" struct variable as a way to declare private data for my CFCs. All my getters and setters have keys in the "instance" struct.
So, my code looks like:
<cfcomponent>
<cfset instance = structNew() />
<cfset instance.private = "Dan Switzer" />
<cffunction name="getPrivate" returntype="string">
<cfreturn instance.private />
</cffunction>
<cffunction name="setPrivate" returntype="void">
<cfargument name="arguments.input" />
<cfset instance.private = arguments.input />
<cfreturn />
</cffunction>
</cfcomponent>
If all variables suddenly become local variables only, I have no way to access the "instance" variable. I don't want to use the "this" scope, because that's a public property accessible from the pages that invoke the component. I want my data private and only accessible to my CFC logic.
So, while the "var" keyword definitely feels kludgey, it has its uses. Yes, they could have solved it a different way, but that road was crossed along time ago.
As Mark Mandel pointed out, I just wish I could "var" a variable anywhere w/in my function (like I can in most other scripting languages.) That certainly would help me to keep my bugs down from unscoped variables.
Whereas if you had done this:
<cffunction name="getPrivate" >
<cfset instance = structNew() />
<cfset instance.private = "Dan Switzer" />
</cffunction>
Then the instance variable *should* be local to that one function. As if you had typed: <cfset var instance = structNew()/>
Since we're just dreaming here, to make things even more fun...
<cffunction name="getPrivate" >
<cfset instance = structNew() />
<cfset instance.private = "Dan Switzer" />
<cfreturn this/>
</cffunction>
I think when a function returns THIS, then the local (function level) "instance" variable should become local (CFC level, still not public from the calling template). In other words when you return THIS it should work just like when you defined it before cffunctions.
Granted, this is all just a pipe dream and it's never going to happen.
Well... not with that attitude.
The problem, as I see it, is that the setter by default would set a local variable--not the global variable. How is CF supposed to know that you want to set the global and not a local variable? Anything you do to automate the process brings in scoping issues.
At least w/the var keyword you have explicit control over whether the variable is global or local to the current function.
I guess the thing that doesn't bother me is that most other scripting language would behave this way--which is probably why Macromedia choose this method. The problem is, CF isn't really like most other scripting languages.
A variable cfset above the functions is local to the CFC. A variable set inside of a function checks to see if it already exists at the CFC level, if so it updates the value and keeps it at that level. If it does not exist at the CFC level it automatically gets var'd behind the scenes.
Is this really any more complex than a single (maybe a few) if statements? I can picture how to do the logic in my head using structkeyexists().
If CF *were* like other scripting languages why would we pay $1200 for a copy of it?
I think the approach that you are suggesting makes thing less consistent. It smacks of having the language make decisions/assumptions for me.
Not only that, but it could still break code. Many times variables-scoped variables are first set in an init() method. Now, mine are all explicitly put in variables scope for clarity, but there is bound to be plenty of code where that isn't the case.
Steve (Bryant), CF makes all sorts of decisions and assumptions for you. If I thought hard enough for 5 minutes I could probably list out 50 assumptions it makes for you.
1) Let me var anywhere:
<cfscript>
for (var i = 0; i LTE 10; i++)
</cfscript>
2) automatically created variables should be automatically var'ed. If I want them available beyond the function, then I'll do that.
Oh, and how about
3) How about letting me do the following:
<cfquery name="var PeopleSelect">...
A solution occurs to me and I don't think it would break existing applications:-
A new attribute in the CFCOMPONENT tag that tells coldfusion that you want all new variables within functions to be created in the var scope. e.g <cfcomponent funcvarlocal="true"....> Then if you wanted to asign something in the variables scope of the cfc you could either explictly reference the scope or trust coldfusion to find the right scope if you had previously declared it.
The result is that var is not depricated but would not need to be used in cfcs with the new attribute. Everybody wins!
Ah, yes, if the default were false, this would indeed solve the problem. I'd use it.
Another idea occurred to me in bed last night as I was dropping off to sleep. To help us cope with the current situation and avoid having to go back to the top of the function everytime a new variable is required:
Declare <cfset var my = StructNew()>. Then use this structure for any local simple variables or queries: <cfquery name="my.qryNew"...>, <cfloop index="my.i"....> etc.. You might still want to declare separate var scope variables for your return structure or other complex objects.
This idea came out of what Jaime Metcher said above about the way Perl uses 'my' as a way of declaring local variables.