How do I declare a local variable within a hotkey in AutoHotkey? - scope

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
}

Related

dmlc throws "unknown identifier" without using #if

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.

Get a symbol's value by its name in a sub

I'm making a package, where I have to get a symbol's value by its name in a sub, while the symbol is defined outside the sub.
Here is the simplified code, it works as expected:
#! /usr/bin/env perl6
sub dump_value($symbol) {
say ::("$symbol")
}
# usage:
my $x = 10;
dump_value('$x');
# expected output: 10
# actual output: 10
Then I put the 'dump_value' in a standalone file as below:
# somelib.pm6
unit module somelib;
sub dump_value($symbol) is export {
say ::("$symbol")
}
# client.pl6
#! /usr/bin/env perl6
use lib ".";
use somelib;
my $x = 10;
dump_value('$x');
The compiler complained:
No such symbol '$x'
in sub dump_value at xxx/somelib.pm6 (somelib) line 3
in block <unit> at ./client.pl6 line 8
Following are some experiments. None of them succeeded.
say ::("MY::$symbol")
say ::("OUR::$symbol")
say ::("OUTER::$symbol")
say ::("CLIENT::$symbol")
...
So how to fix the code?
UPDATE:
Thank you! CALLERS::($symbol) solved my original problem. But in a bit more complex situation, the complier complained again:
# somelib.pm6
unit module somelib;
sub dump_value(#symbols) is export {
# output: 6
say CALLERS::('$x');
# error: No such symbol 'CALLERS::$x'
say #symbols.map({ CALLERS::($^id) } )
}
# client.pl6
#! /usr/bin/env perl6
use lib ".";
use somelib;
my $x = 6;
my $y = 8;
dump_value(<$x $y>);
UPDATE AGAIN:
use OUTER::CALLERS::($^id).
UPDATE AGAIN AND AGAIN:
After I put the 'dump_value' in another sub, it didn't work any more!
# somelib.pm6
unit module somelib;
sub dump_value(#symbols) is export {
say #symbols.map({ OUTER::CALLERS::($^id) } )
}
sub wrapped_dump_value(#symbols) is export {
dump_value(#symbols)
}
#! /usr/bin/env perl6
use lib ".";
use somelib;
my $x = 6;
my $y = 8;
# ouput: (6 8)
dump_value(<$x $y>);
# error: No such symbol 'OUTER::CALLERS::$x'
wrapped_dump_value(<$x $y>);
According to the documentation:
An initial :: doesn't imply global. Here as part of the interpolation
syntax it doesn't even imply package. After the interpolation of the
::() component, the indirect name is looked up exactly as if it had
been there in the original source code, with priority given first to
leading pseudo-package names, then to names in the lexical scope
(searching scopes outwards, ending at CORE).
So when you write say ::("$symbol") in dump_value() in the somelib package, it will first lookup $symbol in the current scope, which has value '$x' then try to look up $x (also in the current scope), but the variable $x is defined in the caller's lexical scope, so you get the No such symbol '$x' error.
You can refer to the caller's lexical symbol given by the value of $symbol using either:
CALLER::MY::($symbol); # lexical symbols from the immediate caller's lexical scope
or
CALLERS::($symbol); # Dynamic symbols in any caller's lexical scope
see the package documentation page.
Couple of things:
use lib ".";
use somelib;
our $x = 10; # You need to export the value into the global scope
dump_value('$x');
Then, use the global scope:
unit module somelib;
sub dump_value($symbol) is export {
say GLOBAL::("$symbol")
}

Scope of var and variables

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.

variable scope in Tcl inside the procedure

I have below dummy program,
proc main2 {} {
set mainVar 100
proc subproc1 {} {
puts $mainVar
}
subproc1
}
main2
it throws an error can't read "mainVar": no such variable. my question is if I declare a variable (i.e mainVar )in proc isn't that variable should be accessible everywhere inside that proc? why it can't accessible in another proc which is declared inside mainproc proc? please put some light on this
Tcl's procedures do not nest; there is no shared scope at all. The main reason for declaring a procedure inside another one is if you are doing some kind of code generation in the outer procedure (whether of the name, the variable list or the body).
Now, you can simulate a read-only version like this (simplified version; a full-service variant is a lot more complex):
proc closure {name arguments body} {
set vars [uplevel 1 {info locals}]
set prologue {}
foreach v $vars {
upvar 1 $v var
append prologue [list set $v $var] ";"
}
uplevel 1 [list proc $name $arguments $prologue$body]
}
proc main2 {} {
set mainVar 100
closure subproc1 {} {
puts $mainVar
}
subproc1
}
main2
I'll leave making it work correctly with global and arrays (as well as all the other nuances of doing this job properly) as exercises for the reader.

why do we need nested procedures in tcl

Hi i have been working with tcl scripting for almost a year and now understand almost basics of it completely. But today i just came across nested procedures which is kind of strange as i did not get the use of it.
Anyways, i read about nested proc here but did not get the clear idea as of why do we need it.
The article says that since proc's are global in a namespace so to create a local proc you make nested proc's.
proc parent {} {
proc child {} {
puts "Inside child proc";
}
...
}
Now one usage i can think of is like
proc parent {} {
proc child {intVal} {
puts "intVal is $intVal";
}
puts "[::child 10]";
... #some processing
puts "[::child 20]";
... #some processing
puts "[::child 30]";
... #some processing
puts "[::child 40]";
... #some processing
puts "[::child 50]";
... #some processing
}
So now the child proc is local to the parent proc and could be used only inside parent proc. And also as i understand it is useful when you want to do same processing at multiple places inside that parent proc.
Now my confusion is that Is this the only use of nested proc or is there anything else that i did not understand???. I mean the nested proc just seems like a kind of private proc.
So please shed some light on it and help me understand the use of nested proc's.
Tcl doesn't have nested procedures. You can call proc inside a procedure definition, but that's just creating a normal procedure (the namespace used for resolution of the name of the procedure to create will be the current namespace of the caller, as reported by namespace current).
Why would you put proc inside proc? Well, the real reason for doing so is when you want to have the outer command act as a factory, to create the command when it is called. Sometimes the name of the command to create will be supplied by the caller, and sometimes it will be internally generated (in the latter case, it is normal to return the name of the created command). The other case that comes up is where the outer command is some sort of proxy for the (real) inner one, allowing the postponing of the creation of the real command because it is expensive in some fashion; if that's the case, the inner procedure will tend to actually be created with the same name as the outer one, and it will replace it (though not the executing stack frame; Tcl's careful about that because that would be crazy otherwise).
In the case where you really need an “inner procedure” it's actually better to use a lambda term that you can apply instead. That's because it is a genuine value that can be stored in a local variable and which will automatically go away when the outer procedure terminates (or if you explicitly unset the variable or replace its contents). This inner code won't have access to the outer code's variables except via upvar; if you want to return the value while still binding variables, you should use a command prefix and include a bit of extra trickery to bind the variables as pre-supplied arguments:
proc multipliers {from to} {
set result {}
for {set i $from} {$i <= $to} {incr i} {
lappend result [list apply {{i n} {
return [expr {$i * $n}]
}} $i]
}
return $result
}
set mults [multipliers 1 5]
foreach m $mults {
puts [{*}$m 2.5]
}
# Prints (one per line): 2.5 5.0 7.5 10.0 12.5
Using an inner proc to simulate apply
Note that the apply command can actually be simulated by an inner procedure. This was a technique used in Tcl 8.4 and before:
# Omitting error handling...
proc apply {lambdaTerm args} {
foreach {arguments body namespace} $lambdaTerm break
set cmd ${namespace}::___applyLambad
proc $cmd $arguments $body
set result [uplevel 1 [linsert 0 $args $cmd]]; # 8.4 syntax for safe expansion!
rename $cmd ""
return $result
}
This was somewhat error-prone and very slow as it would recompile on each invocation; we don't do that any more!
Tcl does not have nested procs. From the proc man page:
Normally, name is unqualified (does not include the names of any containing namespaces), and the new procedure is created in the current namespace.
(emphasis mine)
To demonstrate:
% namespace eval foo {
proc parent {} {
proc child {} {
puts "the child"
}
puts "the parent, which holds [child]"
}
}
% foo::parent
the child
the parent, which holds
% foo::child
the child
We can still call the "inner" proc directly -- it's not local to the enclosing proc.
One item you missed in the discussion in that wiki page is that to make a proc truly local only to the enclosing proc, one must delete it at the end of the enclosing proc:
% namespace eval foo {
proc parent {} {
proc child {} {
puts "the child"
}
puts "the parent, which holds [child]"
# now, destroy the inner proc
rename child ""
}
}
% foo::parent
the child
the parent, which holds
% foo::child
invalid command name "foo::child"
As to the use of a local proc, I'd agree with you that it's beneficial to encapsulate repetive tasks that are only useful in the current proc. I wouldn't get too hung up on that though: clear documentation or code conventions will do just as well.

Resources