If you don't know what I'm talking about, try this:
<cffunction name="myFunc">
<cfargument name="myArg" default="foobar">
<cfdump var="#local#" label="local and arguments scopes before deleting myArg">
<cfset StructDelete(arguments, "myArg")>
<cfdump var="#local#" label="local and arguments scopes after deleting myArg">
<cfset StructDelete(local, "arguments")>
<cfdump var="#local#" label="local scope after deleting arguments scope">
<cftry>
<cfset writeOutput("myArg still exists, and evaluates to: " & myArg)>
<cfcatch>
<cfset writeOutput("myArg no longer exists")>
</cfcatch>
</cftry>
</cffunction>
<cfset myFunc()>
<cfexit>
If you run that code, you'll find that you can still access a declared argument via an unscoped reference even after deleting both the argument, and the arguments scope. This implies that there is an unnamed scope that contains copies of, or references to the values of, declared arguments. What I'm trying to find out is if there is some way to work with this scope directly, such as an undocumented scope name, or a getter method in the underlying Java. Consider this a purely academic question for now, since I'm pretty sure any use case I might have in mind would be dismissed out of hand by most reputable programmers.
EDIT
I thought it might be useful to provide a breakdown of my current understanding of the UDF scopes since Adam's response kind of blurs the lines. For simplicity, I'll exclude cfc-specific stuff...
Variables that are defined without a scope or the "var" keyword are placed in the calling page's variables scope.
The local scope contains variables that are created during function execution using the var keyword or the local scope name (e.g. local.myvar, local["myvar"]). It also contains the arguments scope.
The arguments scope contains every argument that is declared or passed in the function call. Variables may also be added to or deleted from it during function execution. The arguments scope is a member of the local scope and may be referenced as such (e.g. local.arguments.myvar, local.arguments[1]), but it may also be referenced independently (e.g. arguments.myvar, arguments[1]).
There is a nameless scope that contains a duplicate of every argument that is declared (i.e. included in a cfargument tag, or in the parentheses at the beginning of a function definition in cfscript). I've observed the following characteristics and behaviors related to this scope:
Arguments that are not declared are not added to the nameless scope.
Declaring an argument is the only way to get a variable into the nameless scope, and ColdFusion does not appear to use it in any other circumstance.
Unlike the arguments scope, the nameless scope has no apparent relation to the local scope.
The values of a nameless-scoped variable and its arguments-scoped counterpart are either references to the same value, or are connected to each other in such a way that changing one changes both.
Dynamically adding a new variable to arguments does not add it to the nameless scope (because only declared arguments are added to the nameless scope).
You cannot delete a nameless-scoped variable by conventional means (i.e. StructDelete(), ArrayDeleteAt()). You can delete its arguments-scoped counterpart, but the value will remain available via an unscoped reference. (See Henry's answer for a way to fully delete a declared argument).
Once a declared argument has been deleted from arguments, the value of its nameless-scoped counterpart can be set independently. This remains true even if a variable with the same name is added back to arguments.
The nameless scope exists in CF9 and CF10, but (as Henry and Adam pointed out) not in Railo.
The nameless scope is at the absolute top of CF's scope hierarchy, taking precedence over all other scopes when an unscoped reference is used. This, along with the earlier point about undeletability, are probably the most important things to know about the nameless scope. Contrary to the official documentation, the function-specific scope hierarchy is thus:
In ColdFusion, all arguments are duplicated in the un-named function-local scope at the beginning of each function. This code:
<cfset writeOutput("myArg still exists, and evaluates to: " & myArg)>
is not accessing the arguments scope, it is accessing the function local scope. If you altered your code to access the arguments scope, you will - unsurprisingly - see that the variable no longer exists there.
Railo, incidentally, does not behave like this.
Interesting, this test case has a really weird behaviour. I don't know why myArg
is still available. However, if you scope your var and do this:
<cfset writeOutput("myArg still exists, and evaluates to: " & arguments.myArg)>
Or if instead of structDelete()
, u set it to null
:
<cfset myArg = javacast("null","")>
Then you'll get "myArg no longer exists"
.
It may be an edge case of an optimization of Adobe CF. Railo runs as expected with expected result. You can test it yourself on http://cflive.net/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With