Confusion about global variable Topic is solved

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
byzod
Posts: 89
Joined: 21 Jun 2021, 06:46

Confusion about global variable

11 Mar 2023, 00:09

- converting my script to v2
- function related to global variable not working
- check help page and make it working
- play with the code for further understanding < I'm here now

The part I have problem is a function record and display user click records
The working code after I fixed it:

Code: Select all

#SingleInstance Force
#Requires Autohotkey v2.0+

; coords [{X1,Y1},{X2,Y2}...]
global ClickPosRecords := []

^LButton::
{
   global ClickPosRecords
   MouseGetPos(&x, &y)
   if(!IsSet(ClickPosRecords)){
      ClickPosRecords := []
   }
   ClickPosRecords.Push({X:x, Y:y})
   TagCoords(ClickPosRecords)
}

TagCoords(coords){
   global ClickPosRecords
   tagContent := "Coords: " . ClickPosRecords.length . "`n"
   for coord in ClickPosRecords {
      tagContent .= coord.x . "," . coord.y . "`n"
   }
   ToolTip(tagContent)
}
You ctrl + click somewhere, then tooltip display coordinates you clicked
Then I found something I don't understand, as the document says, if you don't declare the global variable first before assigning it, it's treated as local variable
But this local variable still works like a global variable
Code below removed declaration of global records, but it still works, why?

Code: Select all

#SingleInstance Force
#Requires Autohotkey v2.0+

; coords [{X1,Y1},{X2,Y2}...]
global ClickPosRecords := []

^LButton::
{
   ; global ClickPosRecords
   MouseGetPos(&x, &y)
   ; if(!IsSet(ClickPosRecords)){
      ; ClickPosRecords := []
   ; }
   ClickPosRecords.Push({X:x, Y:y})
   TagCoords(ClickPosRecords)
}

TagCoords(coords){
   ; global ClickPosRecords
   tagContent := "Coords: " . ClickPosRecords.length . "`n"
   for coord in ClickPosRecords {
      tagContent .= coord.x . "," . coord.y . "`n"
   }
   ToolTip(tagContent)
}
----

trivial question, as v2 is already a breaking change, why don't just make all built-in function works similar like return value = func(arguments). There're still two types of function styles which is a little bit confusing
I mean functions like MouseGetPos should be works like {x:0,y:0,win:blahobj, control:blahobj} = MouseGetPos(flag)
User avatar
boiler
Posts: 17399
Joined: 21 Dec 2014, 02:44

Re: Confusion about global variable

11 Mar 2023, 03:04

byzod wrote: Code below removed declaration of global records, but it still works, why?
Global variables wrote:Any variable reference in an assume-local function may resolve to a global variable if it is only read.
guest3456
Posts: 3469
Joined: 09 Oct 2013, 10:31

Re: Confusion about global variable

11 Mar 2023, 04:54

boiler wrote:
11 Mar 2023, 03:04
Global variables wrote:Any variable reference in an assume-local function may resolve to a global variable if it is only read.
thought v2 was meant to remove this "common source of confusion".. guess not

neogna2
Posts: 600
Joined: 15 Sep 2016, 15:44

Re: Confusion about global variable  Topic is solved

11 Mar 2023, 16:55

To expand on boiler's reply, the doc says

https://www.autohotkey.com/docs/v2/Functions.htm#Global
Any variable reference in an assume-local function may resolve to a global variable if it is only read. However, if a variable is used in an assignment or with the reference operator (&), it is automatically local by default. This allows functions to read global variables or call global or built-in functions without declaring them inside the function, while protecting the script from unintended side-effects when the name of a local variable being assigned coincides with a global variable.
Which is straightforward in the case of variables that store strings or numbers. For example

Code: Select all

a := 1  ;creates global variables (auto-execution thread is global)
b := "hello"
c := 123
d() {
    MsgBox b  ;hello (only reading, so global variable b's value is read)
    a := 3    ;assignment, so local variable is created
    MsgBox a  ;3 (local variable's value)
    global c := 456 ;global keyword, so assign new value to existing global variable
}
d()
MsgBox a ;1 (unchanged)
MsgBox c ;456 (was changed in function)
But here is something that is easy to miss: In cases where a global variable stores an object (Map, Array, or any other Object) then that variable can later be used inside functions to write data to the object, create new object properties and so on without declaring the variable as global inside the function.

For example

Code: Select all

Obj1 := Array(123, 456) ;creates object in global scope (auto-execution thread is global)
a() {
    global Obj2 := Object() ;also creates object in global scope when function is called
}
a()
b() {
    ;no global keyword needed here for the changes below to be global
    Obj1.Push(789)    ;push number value to global array object in MyObj1
    Obj2.x := "hello" ;create new property with string value to global object in Obj2
}
b()
MsgBox Obj1[3]  ;789
MsgBox Obj2.x   ;hello
That's also what happens in @byzod's second code example in OP when the line ClickPosRecords.Push({X:x, Y:y}) writes data to the global Array object from inside a function even when there is no global ClickPosRecords line inside that function.

So in cases with global variables that store objects it is important to see not only the doc's "if it is only read" sentence but also the doc's next sentence "However, if a variable is used in an assignment or with the reference operator (&), it is automatically local by default" and keep in mind the difference between assigning a variable to store an object and using an existing global variable that stores an object to make changes to that object (such as adding properties, changing property values or pushing values to an array).

The "if a variable is used in an assignment" phrase should be read as covering cases like Obj3 := Object() (assigning to the variable itself to store an object) but not cases like Obj4.x := 123 (assigning a value to a property of an object that is already stored in a variable).

Here is an example with objects that shows how assignments to variables inside a function creates local variables with the same name as (but distinct from) the global variables.

Code: Select all

a := Array(111)	;global
b := Array(222)
c() {
    a := 3    ;assignment, so creates local variable storing number
    MsgBox a  ;3
    b := Array(333) ;assignment, so creates local variable storing Array object with data
}
c()
MsgBox a[1] ;111 (unchanged)
MsgBox b[1] ;222 (unchanged)
I think the doc would benefit from expanded explanations of these things and examples like those above.
Last edited by neogna2 on 12 Mar 2023, 06:01, edited 6 times in total.
byzod
Posts: 89
Joined: 21 Jun 2021, 06:46

Re: Confusion about global variable

12 Mar 2023, 00:50

neogna2 wrote:
11 Mar 2023, 16:55
To expand on boiler's reply, the doc says

https://www.autohotkey.com/docs/v2/Fun...
Thanks for the detailed explanation
So if I want to make sure the code works as I expected, the safest way is always use local localVarName := blah and global globalVarName := blah?
neogna2
Posts: 600
Joined: 15 Sep 2016, 15:44

Re: Confusion about global variable

12 Mar 2023, 05:50

@byzod I don't know if there is one way that is best. It is more a matter of understanding the stuff from the examples above and the difference between assigning a variable and setting an object property (or otherwise writing data to an existing object) and then choosing a coding style that fits best for you.

For example some use global a := 1 even in the auto execution thread even though that thread is already global. Just as a reminder to themselves that that variable will be read inside functions later. Similarly some use global a at the start of a function even when that global variable will only be read, again just as a reminder to themselves that it comes from outside the function.

The opposite alternative is to use keywords global and local only when required and in all other cases just remember the rules.

Again I think the documentation would benefit from expanding on this topic. So I'm pinging in @Ragnar and @lexikos here to see what they think about that and if they agree with my description of the state of things in my previous post.
User avatar
mikeyww
Posts: 27372
Joined: 09 Sep 2014, 18:38

Re: Confusion about global variable

12 Mar 2023, 07:17

Hello,

Lexikos has already posted discussion about the rationale for variable scope in v2.

This is my summary of scope but I think essentially reiterates what is here and in the documentation. viewtopic.php?p=501239#p501239
neogna2
Posts: 600
Joined: 15 Sep 2016, 15:44

Re: Confusion about global variable

12 Mar 2023, 07:36

mikeyww wrote:
12 Mar 2023, 07:17
This is my summary of scope but I think essentially reiterates what is here and in the documentation. viewtopic.php?p=501239#p501239
Yeah I agree with what you write there :thumbup: It is just that your summary and the cited documentation section doesn't mention the case of variables storing objects which may leave some users uncertain or confused until they test things out themselves. I'm only pinging in people on how the documentation could be changed to explain that case better. I'm fine with the v2 global scope rules.
User avatar
mikeyww
Posts: 27372
Joined: 09 Sep 2014, 18:38

Re: Confusion about global variable

12 Mar 2023, 07:44

I agree that this is not particularly clear regarding objects and could benefit from clarification in some places in the docs. Redundancy in moderation can help! There is a separate forum board for suggestions about the documentation, too.

The information below seems to be one key to understanding the nature of objects.
Objects are not contained; they are referenced. For example, alpha := [] creates a new Array and stores a reference in alpha. bravo := alpha copies the reference (not the object) to bravo, so both refer to the same object. When an array or variable is said to contain an object, what it actually contains is a reference to the object.
https://www.autohotkey.com/docs/v2/Concepts.htm#objects
byzod
Posts: 89
Joined: 21 Jun 2021, 06:46

Re: Confusion about global variable

16 Mar 2023, 07:49

mikeyww wrote:
12 Mar 2023, 07:44
I agree that this is not particularly clear regarding objects and could benefit from clarification in some places in the docs. Redundancy in moderation can help! There is a separate forum board for suggestions about the documentation, too.

The information below seems to be one key to understanding the nature of objects.
Objects are not contained; they are referenced. For example, alpha := [] creates a new Array and stores a reference in alpha. bravo := alpha copies the reference (not the object) to bravo, so both refer to the same object. When an array or variable is said to contain an object, what it actually contains is a reference to the object.
https://www.autohotkey.com/docs/v2/Concepts.htm#objects
If I understand it correctly, my confusing here is the definition of only read in doc:
Functions are assume-local by default. Variables accessed or created inside an assume-local function are local by default, with the following exceptions:

Global variables which are only read by the function, not assigned or used with the reference operator (&).
AHK: Change variable arr by arr.push(value) is count as read, it's not assignment or use as reference
Me: Change the content of arr by arr.push(value) count as write operation, not read

AHK is true for most language, change value/member/property of a variable won't change the pointer/reference of this variable
But AFAIK, there's no "auto detection if is global" in many language, you are required to use it explicitly, thus confusing can be avoided, theoretically

For example, var1 is a global variable, var1.showhelloworld() is not a assigment so I can use var1 in localFunc implicitly
But what if I call var1.changeMyReference() when I think I'm messing with local variable var1
User avatar
mikeyww
Posts: 27372
Joined: 09 Sep 2014, 18:38

Re: Confusion about global variable

16 Mar 2023, 08:34

If you are suggesting changes to AutoHotkey as a program, you will need to contact the authorities about that! :) Wish list
byzod
Posts: 89
Joined: 21 Jun 2021, 06:46

Re: Confusion about global variable

16 Mar 2023, 09:48

mikeyww wrote:
16 Mar 2023, 08:34
If you are suggesting changes to AutoHotkey as a program, you will need to contact the authorities about that! :) Wish list
I'm not familiar with how program language works :think:
Just felt confusing and there might be a clear way but I don't know how it should be like :crazy:

Return to “Ask for Help (v2)”

Who is online

Users browsing this forum: emp00, macromint and 77 guests