Initializing vars inside a function Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
zvit
Posts: 224
Joined: 07 Nov 2017, 06:15

Initializing vars inside a function

Post by zvit » 19 May 2022, 13:54

I am trying to declare a global variable inside a function and would like to know why it does not work and if there is a workaround without sending arguments.

This works, but is not what I need:

Code: Select all

global str := "I love being a global str"
TestFunction()

TestFunction(){
    msgbox % str
}
ExitApp
These two suit my needs but don't work:

Code: Select all

TestFunction()

TestFunction(){
    InitializeVars()
    msgbox % str
}

InitializeVars(){
    global str := "I love being a global str" 
}
ExitApp

Code: Select all

InitializeVars()
TestFunction()

TestFunction(){
    msgbox % str
}

InitializeVars(){
    global str := "I love being a global str" 
}
ExitApp

User avatar
mikeyww
Posts: 26599
Joined: 09 Sep 2014, 18:38

Re: Initializing vars inside a function

Post by mikeyww » 19 May 2022, 14:00

Global variables:
To refer to an existing global variable inside a function (or create a new one), declare the variable as global prior to using it.

User avatar
zvit
Posts: 224
Joined: 07 Nov 2017, 06:15

Re: Initializing vars inside a function

Post by zvit » 20 May 2022, 02:43

mikeyww wrote:
19 May 2022, 14:00
Global variables:
To refer to an existing global variable inside a function (or create a new one), declare the variable as global prior to using it.
That's what I did in my second example; I declare\create it with InitializeVars(). It's just like the first example in the link you provided:

Code: Select all

LogToFile(TextToLog)
{
    global LogFileName  ; This global variable was previously given a value somewhere outside this function.
    FileAppend, %TextToLog%`n, %LogFileName%
}

What am I doing wrong?

User avatar
zvit
Posts: 224
Joined: 07 Nov 2017, 06:15

Re: Initializing vars inside a function

Post by zvit » 20 May 2022, 02:56

I'm still confused. In this example, the first msgbox works and the second one inside TestFunction() doesn't. Why?
The fisrt msgbox works because I declared the variable as global prior to using it. So if it was already declared, why isn't it working in the second msxbox?

Code: Select all

InitializeVars()
msgbox % str " Outside a function"
TestFunction()

TestFunction(){
    msgbox % str " Inside a function"
}

InitializeVars(){
    global str := "I love being a global str" 
}
ExitApp
If I pass it to TestFunction() then it works, but that's not what I need.

Code: Select all

InitializeVars()
msgbox % str " Outside a function"
TestFunction(str)

TestFunction(Mystr){
    msgbox % Mystr " Inside a function"
}

InitializeVars(){
    global str := "I love being a global str" 
}

Rohwedder
Posts: 7551
Joined: 04 Jun 2014, 08:33
Location: Germany

Re: Initializing vars inside a function

Post by Rohwedder » 20 May 2022, 03:12

Hallo,
try:

Code: Select all

TestFunction()

TestFunction(){
	global
    InitializeVars() ; creates the global variable str
    msgbox % str
	;since TestFunction() is global, it can read to the global variable str
}

InitializeVars(){
	global str := "I love being a global str"
}
or:

Code: Select all

global str ; creates the super global variable str

TestFunction()

TestFunction(){
    InitializeVars() ; fills the super global variable str
    msgbox % str
	; TestFunction() can read the super global variable str
}

InitializeVars(){
	str := "I love being a super global str"
}

User avatar
zvit
Posts: 224
Joined: 07 Nov 2017, 06:15

Re: Initializing vars inside a function

Post by zvit » 20 May 2022, 04:27

Those work, but I'll explain why it doesn't fit what I need.

I have a file, "Globals" in my lib folder. So, yes, if I put global str := "I love being a global str" in my Globals.ahk file, and added #include<Globals> to all my other script files, it would work. But since if each function name starts with Globals_, then you don't have to use #include<Globals> in all the script files for the functions to work, I'm trying to avoid having to use #Include.

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. Thus, the Globals.ahk in the lib folder.

Your first example works but I would have to put

Code: Select all

global
    InitializeVars()
in EVERY single function of every ahk script file, which of course doesn't make sense.

What I want is to declare global vars in Globals.ahk in the lib folder, and have all my ahk files being able to use those vars, without having to use #include Globals in each of the files.

User avatar
mikeyww
Posts: 26599
Joined: 09 Sep 2014, 18:38

Re: Initializing vars inside a function

Post by mikeyww » 20 May 2022, 05:01

Use #Include! So easy....

Rohwedder
Posts: 7551
Joined: 04 Jun 2014, 08:33
Location: Germany

Re: Initializing vars inside a function

Post by Rohwedder » 20 May 2022, 05:11

Yes!
𝄞 Always Look On The Bright Side Of Autohotkey!

User avatar
boiler
Posts: 16768
Joined: 21 Dec 2014, 02:44

Re: Initializing vars inside a function

Post by boiler » 20 May 2022, 05:13

zvit wrote: The fisrt msgbox works because I declared the variable as global prior to using it. So if it was already declared, why isn't it working in the second msxbox?
When you declare a variable as global within a function, you are allowing that function to see that variable that is within the global variable scope (the area outside any functions). It is not declaring it as a super-global so that other functions can also see it. To declare a variable as super-global, you must declare it as global outside of any function.

User avatar
zvit
Posts: 224
Joined: 07 Nov 2017, 06:15

Re: Initializing vars inside a function

Post by zvit » 20 May 2022, 05:15

Got it. Not possible. Include it is then.

User avatar
mikeyww
Posts: 26599
Joined: 09 Sep 2014, 18:38

Re: Initializing vars inside a function

Post by mikeyww » 20 May 2022, 05:15

Well now, someone had to go and explain all of this so that it makes sense.... :D

User avatar
boiler
Posts: 16768
Joined: 21 Dec 2014, 02:44

Re: Initializing vars inside a function

Post by boiler » 20 May 2022, 05:21

:D I have always thought that the term “global” could lead one to believe that it is available anywhere, so I thought that was perhaps what was happening here. I think there could be a better term to define the space outside of all functions than “the global namespace” (the outer namespace?), but none of that is changing now.

lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: Initializing vars inside a function  Topic is solved

Post by lexikos » 20 May 2022, 07:46

"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. :twisted:

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.

User avatar
zvit
Posts: 224
Joined: 07 Nov 2017, 06:15

Re: Initializing vars inside a function

Post by zvit » 20 May 2022, 08:03

lexikos wrote:
20 May 2022, 07:46
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).
I knew that. But when they are outside a function, the only way to use them in other scripts would be to use #include, which I wanted to avoid. But as I said, this is what I did now.
lexikos wrote:
20 May 2022, 07:46
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.
I didn't mean it doesn't make sense technically... I meant that it's redundant to add that to every function in every ahk file.

User avatar
boiler
Posts: 16768
Joined: 21 Dec 2014, 02:44

Re: Initializing vars inside a function

Post by boiler » 20 May 2022, 08:26

That is a good analogy between international waters in that every nation has access to them if they choose to, but it can also be looked at as every nation already has access to them. They don't have to opt in by declaring their intention before accessing them.

If I were to tell someone that their cell phone plan works globally, I would think most would take it to mean that it would operate everywhere -- in every nation function.

I personally don't mind the term global, but I can see how it can lead to confusion to those that are new to it. If you ever chose to use the term "outer space" in a future version of AHK, I'm all for it! :D

lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: Initializing vars inside a function

Post by lexikos » 21 May 2022, 05:06

zvit wrote:
20 May 2022, 08:03
But when they are outside a function, the only way to use them in other scripts would be to use #include, which I wanted to avoid.
I didn't address that directly before because it seemed frivolous. You would choose to use Globals() in every function rather than #Include <Globals> once in each script? Why?

boiler wrote:
20 May 2022, 08:26
They don't have to opt in by declaring their intention before accessing them.
No, but I suppose they have to build boats. ;)

And I suppose they literally declare imports and exports.
If I were to tell someone that their cell phone plan works globally, I would think most would take it to mean that it would operate everywhere -- in every nation function.
Maybe it would work in many nations, and some areas within those nations, but not every nation or everywhere. Only in places that have agreements between network providers, and coverage. So I guess "someone" would be having a misconception analogous to the one that started this topic.

Post Reply

Return to “Ask for Help (v1)”