drum Posted January 8, 2013 Posted January 8, 2013 Having spent the afternoon debugging a recursive function I wrote, am I right in thinking that local variables are shared amongst all instances of a function. i.e. be very very careful writing a recursive loop.
Moderators Melba23 Posted January 8, 2013 Moderators Posted January 8, 2013 drum,Normally I would not expect Local variables to be shared between recursive functions. But if you post a short reproducer of what exactly you are trying to do you we can be more precise. Certainly you do need to be very careful with recursion. Have you read the Recursion tutorial in the Wiki? M23 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 columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area
kylomas Posted January 8, 2013 Posted January 8, 2013 (edited) drum,Interesting question. Per doc a variable local to a function is destroyed when the function ends. Now the kicker, does a recursed function ever end?kylomasedit: stupid statement as bowmore has demonstrated Edited January 8, 2013 by 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
Bowmore Posted January 8, 2013 Posted January 8, 2013 Run this little test and you will see that variables are not shared unless declared as static Test() func Test() Local $a Static Local $b $a += 1 ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $a = ' & $a & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console $b += 1 ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $b = ' & $b & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console if $b > 1000 Then return Test() EndFunc "Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to build bigger and better idiots. So far, the universe is winning."- Rick Cook
BrewManNH Posted January 8, 2013 Posted January 8, 2013 (edited) If you run this in Scite, you will see that in the first function $Test gets reset after every call to the Test function. In the second function, because I'm using the Static command, $Test doesn't get reset. Local $Count = 1 Test() $Count = 1 Test2() Func Test() Local $Test=1 ConsoleWrite("Running function Test - $Test = " & $Test & @CRLF) $Count += 1 If $Count = 10 Then Return $Test += 1 Test() EndFunc Func Test2() Local Static $Test=1 ConsoleWrite("Running function Test2 - $Test = " & $Test & @CRLF) $Count += 1 If $Count = 10 Then Return $Test += 1 Test2() EndFunc If you mean something different, please explain. EDIT: Bowmore beat me to it. Edited January 8, 2013 by BrewManNH If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag GudeHow to ask questions the smart way! I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from. Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays. - ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script. - Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label. - _FileGetProperty - Retrieve the properties of a file - SciTE Toolbar - A toolbar demo for use with the SciTE editor - GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI. - Latin Square password generator
drum Posted January 8, 2013 Author Posted January 8, 2013 The behaviour as described is what I would expect, however it is not what I am seeing. I have a group of documents (inside an application that I'm automating), I step through each document in the group, and perform some tasks, however every so often there is a sub group, I call the same function, but point it to the subgroup. However when it returns from the subgroup the position in the main group has changed to the last position in the sub. I have step through it in the debugger to confirm this is the case. And it is defintitely not set as static.
Moderators Melba23 Posted January 8, 2013 Moderators Posted January 8, 2013 drum, As I said above, please post the code you used - or a short reproducer. Otherwise we are just whistling in the dark. M23 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 columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area
drum Posted January 8, 2013 Author Posted January 8, 2013 drum, As I said above, please post the code you used - or a short reproducer. Otherwise we are just whistling in the dark. M23 This is the function in question - Not very easy to test but incase you spot an idiot mistake I'll post it. If not I'll try and reproduce the fault in a smaller code later. expandcollapse popupFunc ProcessGroup($Type) Global $root, $sSeries, $sModel, $sYear, $sDocType, $sMainGroup, $sSubGroup, $dtnum $sMainGroup = _ALLTRIM(ControlCommand("TIS", "", "ListBox16", "GetCurrentSelection")) if $Type = "Sub" Then $listbox = "ListBox17" $sSubGroup = _ALLTRIM(ControlCommand("TIS", "", "ListBox17", "GetCurrentSelection")) $group = $sSubGroup else $listbox = "ListBox16" $group = $sMainGroup EndIf $grpnum = ControlCommand("TIS", "", $listbox, "FindString", $group) if $grpnum = 0 Then $grpnum = ControlCommand("TIS", "", $listbox, "FindString", $group&" ") EndIf While $grpnum < _GUICtrlListBox_GetCount(ControlGetHandle("TIS","",$listbox)) if ($Type <> "Sub") And (ControlCommand("TIS", "", "ListBox17", "IsVisible")) Then ControlCommand("TIS", "", "ListBox17", "SetCurrentSelection", 0) Back() Sleep(500) $mngrp = $grpnum ProcessGroup("SUB") $grpnum = $mngrp Else Forward(); Sleep(500) if ControlCommand("TIS", "", "EtkTable3", "IsVisible") Then ProcessDocTable() Back() Else ProcessDoc(1) Back() EndIf EndIf $grpnum = $grpnum + 1 If $grpnum < _GUICtrlListBox_GetCount(ControlGetHandle("TIS","",$listbox)) Then ControlCommand("TIS", "", $listbox, "SetCurrentSelection", $grpnum) Back() Sleep(500) $group = _ALLTRIM(ControlCommand("TIS", "", $listbox, "GetCurrentSelection")) if $Type = "Sub" Then $sSubGroup = $group else $sMainGroup = $group $sSubGroup = "" EndIf EndIf Wend If $Type = "Sub" Then $sSubGroup = "" EndIf EndFunc
Moderators Melba23 Posted January 8, 2013 Moderators Posted January 8, 2013 drum,The first thing that jumps out at me is this line:Global $root, $sSeries, $sModel, $sYear, $sDocType, $sMainGroup, $sSubGroup, $dtnumIf you declare the $sMainGroup and $sSubGroup variables as Global it is hardly surprising that you carry over the values between recursive calls. M23 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 columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area
drum Posted January 8, 2013 Author Posted January 8, 2013 drum, The first thing that jumps out at me is this line: Global $root, $sSeries, $sModel, $sYear, $sDocType, $sMainGroup, $sSubGroup, $dtnum If you declare the $sMainGroup and $sSubGroup variables as Global it is hardly surprising that you carry over the values between recursive calls. M23 The function is deisned to handle those variables, as it steps through things and can then se parent groups etc. the problem variable is $grpnum
AutoBert Posted January 8, 2013 Posted January 8, 2013 Just use local vataibles in your function instead of global.
drum Posted January 8, 2013 Author Posted January 8, 2013 Just use local vataibles in your function instead of global.The variable in question is a local $grpnum
Moderators Melba23 Posted January 8, 2013 Moderators Posted January 8, 2013 drum,Without the external app and the rest of the script so the code actually runs, it is almost impossible to debug that function as we have no real idea what is going on inside it - particularly as ther are no commnets or hints as to the code meaning. All I can say is that declaring variables as Global inside a function is bad coding practice and could (will) lead to all sorts of problems if the function is recursive. In any event I would strongly suggest that if you continue to have problems you recast the script to be iterative rather then recursive - much as shown in the tutorial to which I linked above. M23 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 columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area
drum Posted January 8, 2013 Author Posted January 8, 2013 One thing I did notice is in the examples variables are often declared as "LOCAL" where as I have just used them assuming they would default to LOCAL, I'm wondering if maybe this isn't too reliable. I did say the code wouldn't be easy to follow, I've got to step away from the keyboard shortly, but when I return I'll try redfining the offending variable local, to see if changes anything.
Moderators Melba23 Posted January 8, 2013 Moderators Posted January 8, 2013 drum,AutoIt automatically scopes any variables in the main script as Global and any within Func...EndFunc definitions as Local - although we normally suggest that variables are explicitly scoped. I have not noticed any tendancy for this automatic scoping to be unreliable - and I have no reason to suppose that it is not. I fear you are clutching at straws with that idea. M23 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 columnsChooseFileFolder ---- Single and multiple selections from specified path treeview listingDate_Time_Convert -- Easily convert date/time formats, including the language usedExtMsgBox --------- A highly customisable replacement for MsgBoxGUIExtender -------- Extend and retract multiple sections within a GUIGUIFrame ---------- Subdivide GUIs into many adjustable framesGUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView itemsGUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeViewMarquee ----------- Scrolling tickertape GUIsNoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxesNotify ------------- Small notifications on the edge of the displayScrollbars ----------Automatically sized scrollbars with a single commandStringSize ---------- Automatically size controls to fit textToast -------------- Small GUIs which pop out of the notification area
kylomas Posted January 8, 2013 Posted January 8, 2013 (edited) drum, Don't "poke and hope" that's just going to confuse the issue. Make a reproducer that will demonstrate the problem. This often presents the solution tothe problem as it forces you to r-visit the code in detail, but from a different perspective. With regard to scope. Look at it like this, if the variable is defined outside of a function then it's scope is "global", even though you used the "local" keyword (because it is "local" to the script or file as guinness calls it). If you define a variable within a function using the "local" keyword then the variable only exists for the duration of that function and the scope is local to that function. Obviously, if you define a variable using the "global" keyword then it's scope is "global" regardless of where it is defined. Hope this helps! kylomas Edited January 9, 2013 by 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
czardas Posted January 8, 2013 Posted January 8, 2013 (edited) I'm guessing you mean that after running the function recursively, the code returns to the the following line $grpnum = $mngrp. I am imagining this isn't where you want it to be. $mngrp = $grpnum ProcessGroup("SUB") $grpnum = $mngrp These three lines of code make no sense to me. I don't see how ProcessGroup() modifies $mngrp unless it happens to be a global. There are no global variiables in the code you posted. Edited January 8, 2013 by czardas operator64 ArrayWorkshop
icuurd12b42 Posted January 8, 2013 Posted January 8, 2013 (edited) always use local to define the variables in a function or you will have troubles in the long run, for example for $i loops with undefined scope defaults to global for $i so 2 functions using a for $i loop will interfere with each other (if the seconds function is called in the loop of the first) as for the the code, you never declared your variables so they are all global. I am curious about the working example Local $Count = 1 Test() $Count = 1 Test2() Func Test() Local $Test=1 ConsoleWrite("Running function Test - $Test = " & $Test & @CRLF) $Count += 1 If $Count = 10 Then Return $Test += 1 Test() EndFunc Func Test2() Local Static $Test=1 ConsoleWrite("Running function Test2 - $Test = " & $Test & @CRLF) $Count += 1 If $Count = 10 Then Return $Test += 1 Test2() EndFunc Why can Test and Test2 see $Count... $Count is local... Edited January 8, 2013 by icuurd12b42
kylomas Posted January 9, 2013 Posted January 9, 2013 (edited) icuurd12b42, Because it's scope is "global". Read my previous post for why this is. kylomas edit: additional info Using the same control variable for nested loops is a problem because both loops are updating the same variable, not because of scope. Edited January 9, 2013 by 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
AdmiralAlkex Posted January 9, 2013 Posted January 9, 2013 @icuurd12b42Actually For creates a local variable.The Variable will be created automatically with a LOCAL scope, even when MustDeclareVars is on. .Some of my scripts: ShiftER, Codec-Control, Resolution switcher for HTC ShiftSome of my UDFs: SDL UDF, SetDefaultDllDirectories, Converting GDI+ Bitmap/Image to SDL Surface
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now