Strange situation: "++" VS "+1" Topic is solved

Get help with using AutoHotkey and its commands and hotkeys
padanges
Posts: 24
Joined: 15 Jul 2019, 06:59

Strange situation: "++" VS "+1"

07 Aug 2020, 12:19

Hi there,
I would like to ask someone to share some guidelines for differentiating dynamic variable definitions and pseudo-arrays.
After many hours of debugging my script I've removed most of the code just to find out a strange situation: depending on variable operation the script either fails or succeeds to perform a task. Here's the code:

Code: Select all

#SingleInstance Force
Global imgGuiId
If imgGuiId == ""
	imgGuiId := 0
;; --------------------------- CASE: "++" VS "+1"
;; imgGuiId := imgGuiId + 1
imgGuiId++
;; ---------------------------
Gui guiName%imgGuiId%:New, +HWNDhGuiName%imgGuiId%	;; hGuiName1
Gui guiName%imgGuiId%:Add, Button, +Default +W50 +H20 +GguiName_Enter, ok
GuiControl Hide, ok
Gui guiName%imgGuiId%:Show, w200 h150
Return

guiName_Enter:
	Global imgGuiId
	WinGet actWndId, ID, A
	Loop % imgGuiId
		;; ---------------------------
		;; WHEN "imgGuiId := imgGuiId + 1" is used: FAILS to read "hGuiName%A_Index%" as "hGuiName1" and returns
		;; WHEN "imgGuiId++" is used: SUCCEEDS to read "hGuiName%A_Index%" as "hGuiName1" and closes the gui
		If (actWndId == hGuiName%A_Index%)
			Gui guiName%A_Index%:Destroy
		;; ---------------------------
Return

Esc::ExitApp
You can see that this script closes the window on the Enter keypress, but it fails to do so if one comments out the line "imgGuiId++" and uncomments "imgGuiId := imgGuiId + 1". There should be no difference whether one uses "++" or "+1". I think the problem is, that in one case "hGuiName%A_Index%" is interpreted as a dynamic variable, and in the other - as a pseudo-array. How can I be sure which case is it? And why just by changing the operation syntax from "+1" to "++" I can influence this?
My question is specifically related only to this situation of swapping those code lines - the rest of the code (with dynamic variables) performs as expected (within the rest of the script).
Please, share some thoughts :shock:
gregster
Posts: 5178
Joined: 30 Sep 2013, 06:48

Re: Strange situation: "++" VS "+1"

07 Aug 2020, 12:39

There should be no difference whether one uses "++" or "+1".
Well, there is.
++ will treat blank variables as zero, but only when they are alone on a line (due to backward compatibility, as the docs say), while an expression like imgGuiId := imgGuiId + 1 will not, at all. The latter won't consider it a a valid mathematical operation:
https://www.autohotkey.com/docs/Variables.htm#Operators wrote:Except where noted below, any blank value (empty string) or non-numeric value involved in a math operation is not assumed to be zero. Instead, it is treated as an error, which causes that part of the expression to evaluate to an empty string. And
++ is actually "noted below" as an exception.

So why would imgGuiId be blank in your code, and not 0 ? Because you are using not the right if-syntax:
If imgGuiId == "" should be If (imgGuiId = "") - or If (imgGuiId == ""), if you like, to check for a blank string.

Parentheses make an important difference when used with If - they cause expression mode. If imgGuiId == "" on the other hand, checks for the literal "", not an empty string (like in expression mode).
swagfag
Posts: 4033
Joined: 11 Jan 2017, 17:59

Re: Strange situation: "++" VS "+1"

07 Aug 2020, 12:56

gregster wrote:
07 Aug 2020, 12:39
If imgGuiId == "" on the other hand, checks for the literal "", not an empty string (like in expression mode).
its even worse than that, it checks for the string = ""
padanges
Posts: 24
Joined: 15 Jul 2019, 06:59

Re: Strange situation: "++" VS "+1"

07 Aug 2020, 13:49

Thank you for your comments. I guess you are right - there should be parentheses for IF statement in my code, and "++" provides correct result only because of it's backward compatibility property.

Only now I understand that I have failed to capture the problem properly... I have tried to minimize and simplify the code but I have produced an additional (parentheses) mistake.
So I still have the same problem - the window does not close on Enter, and my suspicions about "dynamic variable VS pseudo-array" seem to hold. But no other ideas. I would appreciate if someone could take a look (at the end of the script I have place a comment "FAILS HERE"):

Code: Select all

#SingleInstance Force

F12::
	RunMe()
Return

RunMe()
{
	Global imgGuiId
	If (imgGuiId == "")
		imgGuiId := 0
	imgGuiId := imgGuiId + 1

	Gui GuiImg%imgGuiId%:New
	Gui GuiImg%imgGuiId%: +HWNDhGuiImg%imgGuiId%
	
	Gui GuiImg%imgGuiId%:Add, Button, +Default +W50 +H20 +GguiImgGroup_Enter, GuiImg%imgGuiId%
	GuiControl Hide, GuiImg%imgGuiId%

	Gui GuiImg%imgGuiId%: Show, Hide ;; render the window, but don't show
	DetectHiddenWindows On
	WinMove % "ahk_id " . hGuiImg%imgGuiId%, , 0, 0, 300, 200
	Gui GuiImg%imgGuiId%: Show, NoActivate, WndTitle %imgGuiId%

	Return
}

guiImgGroup_Enter: ;; react to the "Enter" keypress
	Global imgGuiId
	WinGet actWndId, ID, A
	Loop % imgGuiId ;; image GUI id as a window count
	{
		If 	(actWndId == hGuiImg%A_Index%) ;; FAILS HERE
			Gui GuiImg%A_Index%:Destroy
	}
return

Esc::ExitApp

swagfag
Posts: 4033
Joined: 11 Jan 2017, 17:59

Re: Strange situation: "++" VS "+1"

07 Aug 2020, 14:56

its got nothing to do with pseudoarrays or ++ / +1.
  • u have a function
  • in it u declare the local variable hGuiName<whatever_number_happens_to_be_here>
  • the function goes out of scope, all local variables are cleaned up
  • inside ur globally-scoped Enter button handler-label, u reference the global variable(s) hGuiName<1_through_imgGuiId>. of those, those variables that do not yet exist are created as blank global(NOT super-global) variables(ie their value is an empty string). and those that already do exist(eg on any subsequent label trigger) are blank and contain an empty string
ure comparing hwnds to empty strings. figure out some other way of managing ur variables(store them in arrays/classes/return them/leak them in outer scopes)
padanges
Posts: 24
Joined: 15 Jul 2019, 06:59

Re: Strange situation: "++" VS "+1"

07 Aug 2020, 17:33

Thank you very much, swagfag, I'm reevaluating my variable scopes now, following your recommendations.
But when I change "If (actWndId == hGuiImg%A_Index%)" to "If (actWndId == hGuiImg1)" then the script works as expected.
After reading your guides I understand that no matter how I name the variable, that is, directly ("hGuiImg1"), or indirectly ("hGuiImg%A_Index%") the scope of a variable should stay the same. Strangely, the window closes after using the direct name.
On the other hand, do gui hwnd handles "Gui GuiImg%imgGuiId%: +HWNDhGuiImg%imgGuiId%" become visible to subroutines? When "the function goes out of scope, all local variables are cleaned up" but using "MsgBox %hGuiImg1%" (inside "guiImgGroup_Enter:") I can see the value.
swagfag
Posts: 4033
Joined: 11 Jan 2017, 17:59

Re: Strange situation: "++" VS "+1"  Topic is solved

07 Aug 2020, 19:51

this is too convoluted to explain(and probably understand). basically, if u hardcode a reference to the variable hGuiImg1 in the global scope(ie, the auto-execute section's or that of any label/hotkey/hotstring), at compile time(ie, when the script has loaded) the blank(until assignment) global variable hGuiImg1 will have been created. now, inside ur function(an assume-local function, which is the default):
local variables wrote:•A dynamic variable reference may resolve to an existing global variable if no local variable exists by that name.
  1. the dynamic variable reference hGuiImg%imgGuiId% resolves to hGuiImg1
  2. no local variable by the name of hGuiImg1 exists
  3. the dynamic variable reference hGuiImg%imgGuiId% will now attempt to resolve to global hGuiImg1
  4. a global hGuiImg1 does exist
  5. +HWNDhGuiImg1 assigns a hwnd to the global hGuiImg1
when u check the value of hGuiImg1 at a later point, it does have a value.
if u use dynamic var references only in the global scope, the respective variable wont get declared until the references are evaluated. since u evaluate them much later(in the loop), when ur function runs, step 3. fails, no hwnd gets assigned to anything(other than the local hGuiImg1), so u dont see anything in the label either
padanges
Posts: 24
Joined: 15 Jul 2019, 06:59

Re: Strange situation: "++" VS "+1"

10 Aug 2020, 15:51

First of all, thank you for your comments swagfag! With these dynamic variable references "everyday we stray further from God's light" :D for sure.
Your explanation is complex, but very well expressed. Please, correct me if I'm wrong,- I'll try to put it into a couple sentences - in other words:

"When a script load-up starts resolving dynamic variable names, dynamic variable references stay blank until resolved to an existing local or global variables. If no equivalent explicitly declared ("hard-coded") names are found, then no references are resolved. In such case, for example, when a GUI +HWND option specifies a Global hWnd variable, it cannot be referenced until it ecomes explicitly declared in the script. A dynamic variable reference may resolve to an existing global variable if no local variable exists by that name. On the other hand, if neither local or global variables exist and the usage requires the variable to be created, it is (by default) created as a local variable."

You're right, all this has little to do with pseudoarrays or ++/+1. It's all about variable scopes and variable reference resolutions via equivalent variable names. This explains why simply by having that variable's (hGuiImg1) name declared anywhere* in the script (e.g., by adding "MsgBox %hGuiImg1%" one line above) I was able to get it's value. On the other hand, checking the value of hGuiImg1 at any later point (i.e., after +HWNDhGuiImg1 assigned a hWnd to the Global hGuiImg1) without an explicit variable name declaration, I was unable to get it's value.


So - to fix the problem, one should create a Global array for hWnd variables:

Code: Select all

Global hGuiImgArr
...
hGuiImgArr.Push(hGuiImg%imgGuiId%)
...	
If 	(actWndId == hGuiImgArr[A_Index])
Though, after all, I found a more simple solution for using "Enter" just to close the selected GUI window:

Code: Select all

Gui %A_Gui%:Destroy
;; this line should be excluded from the auto-execution section 
;; because A_Gui is blank until the GUI launches a new thread
padanges
Posts: 24
Joined: 15 Jul 2019, 06:59

Re: Strange situation: "++" VS "+1"

12 Aug 2020, 10:18

It surely would be nice to round up everything by having someone to agree/disagree on my last comments. I'm just trying to figure out what's happening under the AHK hood.
Anyways, thanks for every reply.
swagfag
Posts: 4033
Joined: 11 Jan 2017, 17:59

Re: Strange situation: "++" VS "+1"

12 Aug 2020, 10:42

u dont need these global variables and pseudoarrays. simply return the hwnd when ure done creating the gui and store it somewhere:

Code: Select all

MyGuis := []

F12::MyGuis.Push(newGui())
F13::destroyAllGuis(MyGuis)

newGui() {
	Gui New, +Hwndhwnd
	...
	...

	return hwnd
}

destroyAllGuis(ArrayOfGuiHwnds) {
	for each, hwnd in ArrayOfGuiHwnds
		Gui %hwnd%: Destroy
}

Return to “Ask For Help”

Who is online

Users browsing this forum: Bing [Bot], Google [Bot], mikeyww, monkey5465, yumuffin and 67 guests