Jump to content

if global variables should be avoided, what's the best alternative? (in the included example)


Recommended Posts

I've a general question about the best practice in programming with function in AutoIT or in general:

supposing to have multiple unrelated variables that you set only inside a function and read outside (after) that function, how would you do?

would you declare them as global at the very beginning of the script? or return the variables from the function as an array (losing the useful variable names)? what's the best/most used practice?

I read that global variables should be avoided... but I can't find a better alternative...

Example of how I'ld do such a script, with global variables:

Global $current_song_names, $last_query_PCname, $last_query_time

some code aaaaaa...
query()
some code bbbbbb...
query()
some code cccccc...
query()
some code dddddd...

Msgbox("","", $current_song_names & @CRLF & $last_query_PC_name & @CRLF & $last_query_time)


Func query()
     some code ppppp...
     $current_song_names &= FileRead("c:\current_song_name.txt") & @CRLF
     $last_query_PCname = @ComputerName
     $last_query_time = @HOUR & ":" & @MIN & ":" & @SEC
     some code qqqqq...
EndFunc

How would you do it instead?

Edited by Imbuter2000
Link to comment
Share on other sites

here is one method

Func MsgboxQueryResults()
    Local $current_song_names, $last_query_PCname, $last_query_time
    some code aaaaaa...
    query($current_song_names, $last_query_PCname, $last_query_time)
    some code bbbbbb...
    query($current_song_names, $last_query_PCname, $last_query_time)
    some code cccccc...
    query($current_song_names, $last_query_PCname, $last_query_time)
    some code dddddd...

    Msgbox("","", $current_song_names & @CRLF & $last_query_PC_name & @CRLF & $last_query_time)
EndFunc

Func query(ByRef $current_song_names, ByRef $last_query_PCname, ByRef $last_query_time)
     some code ppppp...
     $current_song_names &= FileRead("c:\current_song_name.txt") & @CRLF
     $last_query_PCname = @ComputerName
     $last_query_time = @HOUR & ":" & @MIN & ":" & @SEC
     some code qqqqq...
EndFunc
Edited by Quual
Link to comment
Share on other sites

  • Moderators

Imbuter2000,

I really would not worry about it too much. The nature of AutoIt makes it difficult to avoid Global variables - so if you feel the need to use them then do so. Personally I would rather have legible code with some sensible Global variables than a psuedo-elegant web of parameters passed between functions - remember you are going to have to maintain this code in the future. ;)

Just try and avoid making every variable in the script Global in scope - that is not the way to go. :D

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

For me the problem I have with globals is when reviewing a script. I ask myself, where did that come from and what should be it be set to? With a long enough script, that can become difficult to answer. If the value is specific, or passed to the function there is no question. Of course to helps to prefix global variables, eg $gsStuff.

About the only variable I prefer to be global when it could be local is magic numbers constants. Because they can help with clarity.

for example

global const $gciStopSign=16
global const $gciYesandNo=4

MsgBox($gciStopSign+$gciYesandNo,"hugh","hello")
Edited by DicatoroftheUSA
Link to comment
Share on other sites

Another common use for Global variables is for flags which are set to trigger events on receiving windows messages. For example to interrupt a running script when clicking on a button. There must be many instances where using globals will be at least the easiest, if not sometimes the only possible solution. I'm absolutely in agreement with all the comments above.

Edited by czardas
Link to comment
Share on other sites

About the only variable I prefer to be global when it could be local is magic numbers constants. Because they can help with clarity.

I would prefer some sort of pre-processor, but you're correct this is a good approach.

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

There isn't a big problem with passing arguments to your functions. This means that you don't have to go scouring your code to find the definition of some global variable which is most likely able to change at any given moment under all sorts of conditions. This is especially pertinent for large code bases. Exceptions to this are native global constants and user defined global constants. If your argument list becomes too long then it's time to look into breaking your function into smaller functions. This helps with comprehension of the code by reducing complexity.

Edited by jaberwocky6669
Link to comment
Share on other sites

Another reason to prefer parameters to globals is that functions can be reused much more easily in other projects. That helps modularity to a great extend: you don't have to practice surgery to export functions and that favors grouping famillies in reuseable includes.

But of course it isn't a strict rule to apply blindly and go away happy in all cases. For instance, writing a function taking 83 arguments is obviously a bad design in the first place.

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

You'll notice that a common theme is coding style. Establishing a variable naming convention is important, especially in a large project.

As far as scope is concerned, consider the following code based on your OP

; scope is local to script making variables in scope to any called fuction

local $current_song_names = '123', $last_query_PCname = 'abc', $last_query_time = '2013, Happy New Year!'

query()
_two()

Func query()
     ConsoleWrite($current_song_names & @lf & $last_query_PCname & @lf & $last_query_time & @lf)

    local $current_song_names = 'hmmm...something changed'  ; scope is local to function query() making the value visible only within this function

    ; from the script perspective there are two variable named $current_song_names at this point, one visible at the script level and one local to this function

    ConsoleWrite('variable after chaged within function = ' & $current_song_names & @LF)
EndFunc

func _two()
    ConsoleWrite($current_song_names & @LF)  ; using the variable with script scope, the var with function scope was destroyed when the func ended
EndFunc

kylomas

Forum Rules         Procedure for posting code

"I like pigs.  Dogs look up to us.  Cats look down on us.  Pigs treat us as equals."

- Sir Winston Churchill

Link to comment
Share on other sites

No need to fear the global variables. If a person does not understand, he rushes from one extreme to another.

Global variables is not a crime. It is important that your script gave the declared results.

When you have a complex script, you will understand how to organize. You won't be able to perceive disordered information.

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...