Jump to content

Question on global scope of variables within function and/or program


Go to solution Solved by poila,

Recommended Posts

I was recently trying to fix a bug in a program I was handed over for about 3 weeks, but has left me stuck for a long while, and asking others in my office is not a viable option. I did a code review on my own and had doubts. So I came here to ask.

What is the default scope of variables when declared within a function, if "Global" and "Local" are not used?

Sample code:

Func showSidebar($guiEvent, $refresh = False)
    If ($refresh) Then
    $previousFormName = Null;
    EndIf
    
    ; Do stuff...

    If $guiEvent <> Null Then
    If $guiEvent[0] == $sideButton_Y Then
        $previousFormName = Null
        $helpStatus = True
    ElseIf $guiEvent[0] == $sideButton_N Then
        $previousFormName = Null
        $helpStatus = False
    EndIf
    EndIf

    ; Do stuff again...
    ; Declaration of variables - does scope change?
    Global $currentForm, $previousFormName, $currentFormName
$currentFormName = ""
$currentForm = WinGetHandle("")

; Do more stuff... If $currentFormName <> $previousFormName Then ; Clear buttons EndIf ; Do even more stuff... $previousFormName = $currentFormName EndFunc

This function would be called within a "While 1" loop when loading a GUI:

While 1
    $guiEvent = GUIGetMsg(1)
    showSidebar($guiEvent)
    Switch $guiEvent[0]
        Case $guiEvent[0] = $blahButton
            ; Do stuff...
    EndSwitch
WEnd

Thing is, when the application runs initially, the variables $currentForm, $previousFormName, and $currentFormName are marked as initially undeclared. But once the function runs, all of them are within Global scope of the application.

If I changed the code such that $currentForm, $previousFormName, and $currentFormName are declared as Global at the beginning of the code, the function would not behave as intended.

As for resetting variables declared Global within the function, is the following code considered okay for resetting variables?

$currentForm = ""
$previousFormName = ""
$currentFormName = ""
Link to comment
Share on other sites

  • Moderators

poila,

 

What is the default scope of variables when declared within a function, if "Global" and "Local" are not used?

By default, AutoIt treats all variables declared outside functions as Global - even if they are declared as Local. All variables declared inside functions are Local, unless specifically declared as Global (which is regarded as poor practice).

You need not respecify the scope when resetting simple variables as they retain their initial scope. But you do need to specify the scope when resetting arrays or you will get a syntax error as array declarations require a scope at all times.

The Variables - using Global, Local and ByRef tutorial in the Wiki should be your next port of call. ;)

M23

Edited by Melba23
Typo

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

poila,

 

By default, AutoIt treats all variables declared outside functions as Global - even if they are declared as Local. All variables declared inside functions are Local, unless specifically declared as Global (which is regarded as poor practice).

You need not respecify the scope when resetting simple variables as they retain their initial scope. But you do need to specify the scope when resetting arrays or you will get a syntax error as array declarations require a scope at all times.

The Variables - using Global, Local and ByRef tutorial in the Wiki should be your next port of call. ;)

M23

That was mildly helpful. I did remember reading that tutorial awhile ago, had abit of trouble with applying scope concepts onto legacy code. I went to play around with my variables' scope just now.

Now I tried rewriting the function like this:

Func showSidebar($guiEvent, $refresh = False)
    Local Static $currentForm, $previousFormName, $currentFormName
    If ($refresh) Then
        If IsDeclared($previousFormName) Then
             $previousFormName = Null;
        EndIf
    EndIf
    
    ; Do stuff...

    If $guiEvent <> Null Then
    If $guiEvent[0] == $sideButton_Y Then
        If IsDeclared($previousFormName) Then
             $previousFormName = Null;
        EndIf
        $helpStatus = True
    ElseIf $guiEvent[0] == $sideButton_N Then
        If IsDeclared($previousFormName) Then
             $previousFormName = Null;
        EndIf
        $helpStatus = False
    EndIf
    EndIf

    ; Do stuff again...
    $currentFormName = Null
    $previousFormName = Null
    $currentForm = WinGetHandle("")

    ; Do more stuff... 
    If $currentFormName <> $previousFormName Then 
        ; Clear buttons 
    EndIf 
    ; Do even more stuff... 
    $previousFormName = $currentFormName 
EndFunc

Unfortunately, the thing is that another function needs to make use of the variable $currentFormName, which previously was in Global scope but because I tried and experimented with Local Static, obviously it seemed to be effective within function showSidebar().

IsDeclared() would cause the script to prevent compiling because it detected $previousFormName as undeclared, though after checking with previous programmer, he mentioned that the way the earlier code shown was written was intentional (hack-ish, I feel).

Also, as I have shown in my earlier post, because showSidebar() is within a While 1 loop, this is called continually until the While loop is exited, meaning that the variable $previousFormName would be continually reset only if I were to use the newer way I wrote.

(The older code I showed meant that though showSidebar() is called continually, $previousFormName is only modified once, so that the sidebar GUI won't reset infinitely.)

$currentForm is used for grabbing GUI handles.

Need to show additional code for possible troubleshooting - this occurred before resetting variables and after $previousFormName = $currentFormName:

$pos = WinGetPos($currentForm)

    If $currentFormName <> "" Then
        If $currentFormName <> $previousFormName Then
            If $sideButton_Y <> Null Then
                GUICtrlSetState($sideButton_Y, $GUI_HIDE)
            EndIf
            If $sideButton_N <> Null Then
                GUICtrlSetState($sideButton_N, $GUI_HIDE)
            EndIf

            GUISwitch($currentForm)
            ; Show help button on main forms
            If $currentFormName == "myCurrentForm" Then
                If $helpStatus Then
                    $sideButton_N = GUICtrlCreateLabel("?", $pos[2] - 44, 2, 20, 20)
                    GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)
                    GUICtrlSetFont(-1, 14, 1000, 0, "Tahoma")
                    GUICtrlSetColor(-1, 0xeeeeee)
                Else
                    $sideButton_Y = GUICtrlCreateLabel("?", $pos[2] - 44, 2, 20, 20)
                    GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)
                    GUICtrlSetFont(-1, 14, 1000, 0, "Tahoma")
                    GUICtrlSetColor(-1, 0xeeeeee)
                EndIf
            EndIf
        EndIf
    EndIf


    If $helpStatus Then
        If $currentFormName <> "" Then
            WinMove($sidebarForm, "", $pos[0] + $pos[2], $pos[1], $const_HelpWidth, $pos[3])

            If $currentFormName <> $previousFormName Then
                calledAnotherFunction()

                ; $currentArrayIndex is some Global array variable, don't think too much about it
                If $currentArrayIndex >= 0 Then
                    ; Do something
                Else
                    showInput("Done!")
                EndIf

                If $currentFormName == "myCurrentForm" Then
                    ; Do something else
                EndIf

                GUISetState(@SW_SHOWNOACTIVATE, $sidebarForm)
            EndIf
        Else
            calledAnotherFunction()
        EndIf
    Else
        calledAnotherFunction()
    EndIf

calledAnotherFunction is as follows:

Func calledAnotherFunction()
    ; Hide stuff
    GUISetState(@SW_HIDE, $sidebarForm)
EndFunc
Link to comment
Share on other sites

  • Moderators

poila,

 

That was mildly helpful

And I find your reply mildly insulting. ;)

 

Unfortunately, the thing is that another function needs to make use of the variable $currentFormName

Then it needs to be Global in scope or passed to the other function as a parameter. :)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

If you don't define the variable in a function as local, and there is already a global match (not case sensitive), the global will be overwritten.

Gotta be careful of that...

$i = 10
Function()
ConsoleWrite($i & @CRLF)
Func Function()
    $i = 30
EndFunc

^output is 30, not 10.

$i = 10
Function()
ConsoleWrite($i & @CRLF)
Func Function()
    Local $i = 30
EndFunc

^output is 10

Edited by jdelaney
IEbyXPATH-Grab IE DOM objects by XPATH IEscriptRecord-Makings of an IE script recorder ExcelFromXML-Create Excel docs without excel installed GetAllWindowControls-Output all control data on a given window.
Link to comment
Share on other sites

I pushed the variables $currentForm, $previousFormName, $currentFormName to the top of source code, declared as Global, outside the function.

Additionally, I did not re-declare the variables in the function to Local.

Earlier code of function "showSidebar", I refactored first part to this:

If $previousFormName <> Null Then
    $previousFormName = Null
EndIf
$currentForm = Null
$currentFormName = Null

; Get currently focused form
$currentForm = WinGetHandle("")

Sidebar GUI keeps flashing instead.

Reason for this refactor was to overcome another issue I need to raise, which is randomly-missing/hiding GUI controls.

Welp?

Edited by poila
Link to comment
Share on other sites

Too late to the party I see. Word of advice to poila, with global variables use a prefix of $g_ e.g. $g_sMyName, as it's easy to distinguish what is local and global.

(not case sensitive)

I really love case-sensitive languages e.g. C#. (100% serious comment)

UDF List:

 
_AdapterConnections()_AlwaysRun()_AppMon()_AppMonEx()_ArrayFilter/_ArrayReduce_BinaryBin()_CheckMsgBox()_CmdLineRaw()_ContextMenu()_ConvertLHWebColor()/_ConvertSHWebColor()_DesktopDimensions()_DisplayPassword()_DotNet_Load()/_DotNet_Unload()_Fibonacci()_FileCompare()_FileCompareContents()_FileNameByHandle()_FilePrefix/SRE()_FindInFile()_GetBackgroundColor()/_SetBackgroundColor()_GetConrolID()_GetCtrlClass()_GetDirectoryFormat()_GetDriveMediaType()_GetFilename()/_GetFilenameExt()_GetHardwareID()_GetIP()_GetIP_Country()_GetOSLanguage()_GetSavedSource()_GetStringSize()_GetSystemPaths()_GetURLImage()_GIFImage()_GoogleWeather()_GUICtrlCreateGroup()_GUICtrlListBox_CreateArray()_GUICtrlListView_CreateArray()_GUICtrlListView_SaveCSV()_GUICtrlListView_SaveHTML()_GUICtrlListView_SaveTxt()_GUICtrlListView_SaveXML()_GUICtrlMenu_Recent()_GUICtrlMenu_SetItemImage()_GUICtrlTreeView_CreateArray()_GUIDisable()_GUIImageList_SetIconFromHandle()_GUIRegisterMsg()_GUISetIcon()_Icon_Clear()/_Icon_Set()_IdleTime()_InetGet()_InetGetGUI()_InetGetProgress()_IPDetails()_IsFileOlder()_IsGUID()_IsHex()_IsPalindrome()_IsRegKey()_IsStringRegExp()_IsSystemDrive()_IsUPX()_IsValidType()_IsWebColor()_Language()_Log()_MicrosoftInternetConnectivity()_MSDNDataType()_PathFull/GetRelative/Split()_PathSplitEx()_PrintFromArray()_ProgressSetMarquee()_ReDim()_RockPaperScissors()/_RockPaperScissorsLizardSpock()_ScrollingCredits_SelfDelete()_SelfRename()_SelfUpdate()_SendTo()_ShellAll()_ShellFile()_ShellFolder()_SingletonHWID()_SingletonPID()_Startup()_StringCompact()_StringIsValid()_StringRegExpMetaCharacters()_StringReplaceWholeWord()_StringStripChars()_Temperature()_TrialPeriod()_UKToUSDate()/_USToUKDate()_WinAPI_Create_CTL_CODE()_WinAPI_CreateGUID()_WMIDateStringToDate()/_DateToWMIDateString()Au3 script parsingAutoIt SearchAutoIt3 PortableAutoIt3WrapperToPragmaAutoItWinGetTitle()/AutoItWinSetTitle()CodingDirToHTML5FileInstallrFileReadLastChars()GeoIP databaseGUI - Only Close ButtonGUI ExamplesGUICtrlDeleteImage()GUICtrlGetBkColor()GUICtrlGetStyle()GUIEventsGUIGetBkColor()Int_Parse() & Int_TryParse()IsISBN()LockFile()Mapping CtrlIDsOOP in AutoItParseHeadersToSciTE()PasswordValidPasteBinPosts Per DayPreExpandProtect GlobalsQueue()Resource UpdateResourcesExSciTE JumpSettings INISHELLHOOKShunting-YardSignature CreatorStack()Stopwatch()StringAddLF()/StringStripLF()StringEOLToCRLF()VSCROLLWM_COPYDATAMore Examples...

Updated: 22/04/2018

Link to comment
Share on other sites

  • Solution

Hi guinness,

I have already renamed my variables according to the standards used in the Best Practices tutorial in the AutoIt Wiki.

eg.) The handle $currentForm is now $g_hCurrentForm (global, handle).

I dug deeper into the problem, and it turned out that the functions/variables that I mentioned in this thread so far aren't the cause of the problem.

It turned out that 2 other global variables - declared uninitialized at the top of source code - were being used and modified within the function "showSidebar()"

If $currentFormName <> "" Then
    ; If focused form on current iteration is different from previous iteration then initiate help sequence
    If $currentFormName <> $previousFormName Then
        ; Remove previous buttons
        If $sideButton_Y <> Null Then
            GUICtrlSetState($sideButton_Y, $GUI_HIDE)
        EndIf
        If $sideButton_N <> Null Then
            GUICtrlSetState($sideButton_N, $GUI_HIDE)
        EndIf
        EndIf
EndIf

I am thinking of extracting out the contents of whatever GUI controls and handles (like showing the contents of an array) somewhat similar in fashion to the WinListChildren() UDF shown in this link: '?do=embed' frameborder='0' data-embedContent>>

Is there a similar function (native or UDF) used for displaying GUI handles into an array/list?

Thanks in advance.

EDIT: It turned out that the 2 global variables I mentioned in this particular reply are the culprit to my predicament. It was more of a fundamental code design flaw rather than the way the functions I shared here were used/written. Thanks again everyone. At the meantime, I might leave the question on how to display member GUI handles into an arraylist as an open question, but probably in another thread. :)

Edited by poila
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...