"Global" doesn't mean "literally available/applicable/accessible/present/...
everywhere" in real life, either.
What else would you call the
waters space outside the jurisdiction of any
nation function? Interfunctional space? Actually, the
global scope does span the entire script, including all functions, just as every nation on Earth is, you know, on Earth. Each function can choose to import variables, but isn't necessarily exposed to them by default. Some functions have tighter borders or stricter policies than others (assume-global < assume-local < force-local). Although other languages tend to be different, even in languages where global variables are accessible by default (which is often because all variables must be declared), there are cases where a global variable could become inaccessible, such as when a local variable or parameter is declared with the same name.
Python uses
nonlocal to import variables from an outer scope (which may or may not be global), but I don't like it. A future AutoHotkey that supports modules might allow
import name to import names from other scopes and modules (but I'll probably change my mind a few times).
If you really want to declare your variables in a single file and trigger it by calling a function, you could gosub out of the function.
Code: Select all
InitializeVars(){
gosub InitInInterfunctionalScope
}
InitInInterfunctionalScope:
global str := "I love being a global str"
return
But if you ever explicitly #include that example in the wrong place, it could have unintended consequences. That can be prevented by messing things up further:
Code: Select all
TestFunction()
TestFunction(){
InitializeVars()
msgbox % str
}
;~ This can be in its own file:
InitializeVars(){
gosub InitInInterfunctionalScope
}
goto NotDoItTwice
InitInInterfunctionalScope:
global str := "I love being a global str"
return
NotDoItTwice:
("This no-op ensures there's no error if a function is defined immediately below")
;~ End initialization file.
ExitApp
There are also strategies actually worth using, such as putting shared values in a class:
Code: Select all
TestFunction()
TestFunction(){
msgbox % G.str
}
class G {
static str := "Essentially global"
}
There is no need to explicitly initialize the class, but there is small runtime overhead when accessing it, because properties are resolved by name each time, whereas global variables are resolved to addresses at load-time.
The other solutions presented were:
- Make the functions assume-global so that they can access all global variables.
This is more error-prone, as all variables will be global by default - even variables that you have not assigned outside of the function.
- Declare the variables at the top of the script file.
This (using super-globals) can still cause errors, if for instance some function (perhaps one you copied from another user, or perhaps one you wrote or will write at a different time) happens to use a variable name in common with your super-global, without intending for it to be global. But weighed against the cost/risk of duplicating variable declarations across each function, it's not so bad.
In your second example, you declare the var inside the main script file. I have over 50 global vars and I don't want to declare them all in hundreds of files.
There is no requirement to declare the variables at the top of the main file, or in the main file at all. They just need to be declared
outside of any function. That can mean at the top of Globals.ahk, or the bottom, or anywhere else that isn't inside a function (and is a valid context for a global declaration).
Your first example works but I would have to put
global
InitializeVars()
in EVERY single function of every ahk script file, which of course doesn't make sense.
Why doesn't that make sense? These variables aren't a standard part of the language, so having an explicit indication that the function relies on them is a good thing.
(And the answer is...) You only need to initialize the global variables once. If you were to call
InitializeVars() at the top of each script, you would not need to duplicate it for every function. If you were to call
InitializeVars() inside the file which defines it, you could just
#include that file at the top of the script.
#Include Globals.ahk could be literally the only thing you add to each script for declaring or initializing those variables. And if you #include it at the top, there doesn't need to be an initialization function at all.
Technically, you don't need to do
any of the following:
- Explicitly #include the file in each script.
- Explicitly call InitializeVars() from each function or script.
- Explicitly declare the variables in each function or script.
...if you use v1.1.34.02 with either of the following:
- The /include command line switch, which can be applied to all scripts you run from Explorer via the registry.
- A copy of globals.ahk embedded as RCDATA resource #2 in AutoHotkey.exe.
However, I wouldn't recommend it if you ever want to run code written by someone else. On the other hand, you can be selective about which scripts you apply either of those solutions to. Just don't forget that your scripts essentially include that extra code.
N.B. With AutoHotkey v2, you do not need to declare global variables unless you want to
assign to them inside a function.
boiler wrote:the outer namespace
Fixed.