If I have a function like
<cfscript>
function say(what) {
var a = what;
variables.b = what;
return what;
}
</cfscript>
I thought the scope of a was variables, but dumping variables returns just b. What is the scope of a?
This really is a comment, but it is way too long. Consider the following code
<cfscript>
function doMath() {
var a = 1;
local.b = 2;
return a + local.b;
}
</cfscript>
At first glance on might think that var and local. have the same scope. After all they both exist only within the function. When then function is done, both variables cease to exist. End of story? Maybe not.
In ColdFusion, we have both implied scopes and implicit scopes.
url.a
form.a
cookie.a
session.a
application.a
local.a
arguments.a
myQuery.a
Are all different. If I have all of the above as valid variables and I say <cfoutput>#a#</cfoutput> which a do I get? ColdFusion goes through its list of implied scopes until it hit one that matches. And that is the one that gets displayed. So back to the question.
So when I am inside of a function, if I use var I am saying to ColdFusion, look through all the implied scopes until you find one that matches. If I use local.a, I am saying look in exactly one place and use that.
Benefits
I know exactly what variable I am picking up. If you are writing code that needs to be as fast as possible you won't use implicit scopes. If you are writing code that is the most readable, you won't use implicit scopes.
So no. var is not the same as local.
Understanding scoping can help you avoid some issues that can be extremely difficult to track down. For all intents an purposes, var a puts a into the local scope, and it can be referenced as a local variable. And if declared afterwards, it will overwrite any a variable already in the local scope.
https://trycf.com/gist/faf04daa53194a5fad2e69e164518299/acf2016?theme=monokai
<cfscript>
function say() {
local.a = "local" ;
var b = "var" ;
lv = local.b ; // We didn't explicitly assign b to Local scope.
try {
v = variables ; // Let's dump the variables scope.
} catch (any e) {
v = "Error: " & e.message ;
}
variables.nh = "Now here." ; // Explicitly populate variables scope.
var c = "var c" ; // We have a variables scope, what happens to var?
try {
v2 = variables ; // Let's dump the variables scope.
} catch (any e) {
v2 = "Error: " & e.message ;
}
var d = "var" ;
local.d = "local" ;
local.e = "local" ;
var e = "var" ;
return {
a : a , // Local.
b : b , // Var.
d : d , // Which one?
e : e , // Which one?
el : local.e , // Which one??
l : lv , // Ref b in local scope.
l2 : local , // Dump local scope.
v : v , // There doesn't seem to be a variables scope yet.
v2 : v2 // Defined a variable scope and now here.
} ;
}
writeDump(say());
</cfscript>
We can see above that declaring var b puts b into the local scope, and that the variables scope doesn't exist until we declare something into it. We can reference local.b, but variables.b can't exist. After we explicitly created and populated variables scope with nh, we create a var c. This doesn't go into the variables scope either, but into the local scope.
When a variable is declared with the same name in either local or by var, the last one declared will overwrite the other one (see d,e and el). Watch out for this.
Also note that the empty arguments scope from the function is also in the local scope.
On that note, my last two observation of scope things to watch out for:
https://trycf.com/gist/65b73e7a57d0434049d0eb9c0d5f9687/acf11?theme=monokai
<cfscript>
function ks() {
variables.jay = "Snoogins." ; // variables scope leaks out of function.
local.silentbob = "____" ; // local scope stays inside function.
}
function sayArgs(arg) {
local.arg = "local" ; // Order after agruments in CF10 but not 2016.
ks() ; // Run ks() function to instantiate jay and silentbob.
return {
arg : arg , // CF10 = arguments scope. CF11+ = local scope.
args : arguments ,
local : local , // No leakage from ks().
vars : variables // Jay leaks from ks().
} ;
}
writeDump(sayArgs("argue")) ;
</cfscript>
Two things I noted here:
First, there is a difference between the order of evaluation of arguments and local scopes in CF10 vs later CF versions. Current CF2016 (or 2011+) behavior is that local scope inside of a function will not overwrite the arguments scope, but it will be evaluated first. The opposite happens in CF10: arguments is evaluated first. Lucee and Railo behave like ACF2016.
The second note has to do with variable leakage as it applies to variables and local. local will only exist inside the function that it is declared in. variables is more global and can be reached outside of the function.
https://helpx.adobe.com/coldfusion/developing-applications/the-cfml-programming-language/using-coldfusion-variables/about-scopes.html << For ACF2016. Displays evaluation order with local over arguments.
http://www.learncfinaweek.com/week1/Scopes/ << Lists the order that ACF10 evaluates in, but the order of arguments and local are switched in later versions.
https://help.adobe.com/en_US/ColdFusion/9.0/Developing/WSc3ff6d0ea77859461172e0811cbec09af4-7fdf.html << This is the documentation for ACF9. It lists the same order as ACF2016, but is different in ACF10. I don't have a copy of CF9 to test against right now, so I don't know how CF9 and earlier handle the evaluations.
Declaring a variable using the var keyword puts it into the local scope, not the variables scope.
Let's go line by line (see the comments):
<cfscript>
function say(what) {
// using the "var" keyword define a variable named "a" in the "local" scope
// the "local" scope is private to the current function context
// give to "a" the value of the "what" argument
var a = what;
// explicitly define a variable "b" in the "variables" scope
// the "variables" scope is available anywhere in the current template context
// give to "b" the value of the "what" argument
variables.b = what;
// return the value of "what" argument
return what;
}
</cfscript>
var is a keyword
variables is a scope
local is a private scope (also a keyword)
The local scope can be populated either using var a = "foo" or explicitly using local.a = "foo".
In the current example, var a is available only within the scope of the function.
Related
Why do I get an unknown identifier error for the fail_test1 template and not in pass_test1?
template pass_test1 {
param len = 10;
#if (true) {
saved int8 data[len];
}
}
group pass is pass_test1;
template fail_test1 {
param len = 10;
saved int8 data[len];
}
group fail is fail_test1;
In short: in pass_test1 the saved declaration is not part of the template type, whereas in fail_test1 it is. And the error message comes from DMLC trying to parse the type of data as a member of the template type.
This happens because saved declarations are normally added to the template type: If you silence the error by s/len/10/, then you can write a run-time reference to it, as local fail_test1 x = cast(fail, fail_test1), and then you can access x.data. However, this does not work for pass_test1: you can write local pass_test1 y = cast(pass, pass_test1) but then you cannot access y.data. Conditional parts of a template cannot be part of the template's type, because there is no reasonable way for the run-time reference to handle the case when the #if condition of the referenced object is false.
A funny consequence is that your #if (true) { saved data[len]; } construct is in fact the recommended idiom for parameterized array members of templates. It looks a bit odd, but it happens to do exactly what you want, and it's uncommon enough that we probably won't invent a special syntax for it.
If you want to access the data member from the template type, then you can get the best of both worlds by writing:
template pass {
param len default 10;
#if (true) { saved int8 _data[len]; }
param data : int8*;
param data = &_data;
}
Here, data is available within the template type, and the array length is still configurable.
TL:DR; I can't declare variables inside a hotkey as local, which means temp and index are globally accessible.
I recently discovered that local variables cannot be declared as local from within a hotkey or if they are used as parameters within a for-loop.
^j::
local temp = Hello, world! ; Error: This line does not contain a recognized action
Return
SampleFunction() {
for local temp in myArray { ; Error: Variable name contains an illegal character
; do stuff
}
}
This becomes an issue with #warn enabled. Unless I remember to use unique variable names for each of my for loops, I run into the following error:
Warning: This local variable has same name as a global variable. (Specifically: index)
For example:
#warn
^j::
index = 42 ; This *index* variable is global
Return
UnrelatedFunction() {
for index in myArray { ; This *index* variable is local
MsgBox % myArray[index]
}
}
In particular this becomes a problem when using imports, as variables from my own scripts often conflict with variables from my imported scripts.
Ideally, I would be able to put a local declaration before any for-loops, but as shown earlier, I'm not able to do this within hotkeys.
Is it possible to declare a variable as local from within a hotkey?
I implement my hotkeys with functions. Variables within functions have by default local scope unless they are declared global
F1::alpha(10,10)
F2::alpha(20,30)
F3::beta()
alpha(x,y)
{
myvar := x*2 + y
}
beta()
{
myvar := 47
}
If 2 threads running together then how global variable will be updated by both threads. Is that value will be conflicted?
This would depend entirely on what you are doing with the global variable being accessed by multiple threads.
Unless the global variable is thread-safe, in the sense that the variable is locked during an operation to change it's value, then it seems likely that you could end up with a race condition occurring.
I am not certain which language you are working with, but it may make sense to create an accessor for the variable (such as a property) which is locked whilst changes are being applied. In C# you could accomplish this easily with the following pseudo-code as an example:
private object _LockObject = new object();
private int _SomeProperty;
public int SomeProperty
{
get { return _SomeProperty; }
set
{
lock (_LockObject)
{
_SomeProperty = value;
}
}
}
The lock ensuring that the code to change the value of the variable is thread-safe (because it is locked during each update operation).
I don't understand why this code is wrong, i just want to encapsulate voids in the dictionary.
private delegate void LotIs(string path);
private Dictionary<int, LotIs> lots = new Dictionary<int, LotIs>
{
{0, this.LotIsBanHummer},
{1, this.LotIsDuck},
{2, this.LotIsToy},
{3, this.LotIsDragon},
{4, this.LotIsMoney}
};
private void LotIsBanHummer(string path)
{
lotImage.Image = LB10_VAR7.Properties.Resources.banhammer2;
StreamReader str = new StreamReader(path + "BunHummer.txt");
textBox1.Text = str.ReadToEnd();
textBox3.AppendText(textBox1.Lines[1].Split(' ')[1]);
}
The compiler does not allow you to use this in such an initializer expression because this is assumed to be uninitialized when the expression is evaluated. Remember that such expressions are evaluated before any constructor has been executed.
Within a constructor the use of this is permitted at any point even though some fields may not have been initialized yet, either, but there, it is within your responsibility to not access any uninitialized members.
In your case, therefore, the solution is to initialize your dictionary/add the initial contents in your constructor (or, in the case of several constructors, in a method that you call from each constructor).
From the C# specification:
17.4.5.2
Instance field initialization
A variable initializer for an instance field cannot refe rence the
instance being created. Thus, it is a compile- time error to reference
this in a variable initializer, as it is a compile-time error for a
variable initializer to reference any instance member through a
simple-name
You can move your initialiser to the constructor however.
use this in a constructor to define Dictionary like that.
like this:
private Dictionary<int, LotIs> lots = new Dictionary<int, LotIs>();
public YourClass() {
lots[0] = this.LotIsBanHummer;
lots[1] = this.LotIsDuck;
lots[2] = this.LotIsToy;
lots[3] = this.LotIsDragon;
lots[4] = this.LotIsMoney;
}
If LotIsBanHummer, LotIsDuck etc are defined static then you can initialize without the this.
My Node.js project suffering memory leaking, I've already set variables to null in closure, I mean, I know code like this:
var a = 0;
var b = 1;
var c = 0;
example_func(c, func(){
console.log(b);
});
Will cause memory leaks, so I add some code to set these variables to null;
var a = 0;
var b = 1;
var c = 0;
example_func(c, func(){
console.log(b);
a = null;
b = null;
c = null;
});
But I still got leaks, so I try to use memwatch-node to figure out what's wrong with my code.
And the result shows that closure causing the leak, but not specified enough to target.
I've got the JSON like this
{ what: 'Closure',
'+': 12521,
size: '520.52 kb',
'-': 5118,
size_bytes: 533016 },
And I am wondering if I could get more specific details about which closure is leaking.
I've assigned name for all closures, but still not work.
You can't get more specific about which closure. memwatch gets a dump of the v8 heap and then takes differences of it and reports leaks if, after 5 successive garbage collection events, that object type count continued to grow.
Also, I believe you are confused on what closures are. The MDN page on closures gives a good description. A closure is not a variable, but a scope that enables functions to retain references and continue to work when used in a part of the code where those variable references would not otherwise be available.
If you pass functions around keep a reference to that function, it's closure could reference other closures. So, it's possible you have a single closure that could have a lot in it.
Do this: disable parts of your code until memwatch stops complaining. Then, look at that code. If you are still confused, post more details in this question.