Sign in to follow this  
Followers 0
boogieoompa

Nested function variables

15 posts in this topic

I have been sniffing around the forum and about an issue and I was wondering if I could get some explicit confirmation. I have a function that is nested within another function. Effectivly I want a function to launch another function and then use some of the variables that the nested function created. Is this possible? Something kind of like

Global $SecondVa

Func Primary()
;do some extra code here
Secondary()
Msgbox(0,Test,$SecondVar)
EndFunc

Func Secondary()
$SecondVar = 15
EndFunc

I know this is very simple and many people might say "why don't you just combine them?" I would but in my case my secondary function is 100 lines of code and I need to call it a couple dozen times. This seems kind of sloppy.

Thanks in advance

Share this post


Link to post
Share on other sites



The definition of your variable is wrong. Global $SecondVa should be Global $SecondVar. Correct that, run script and check the result. You will see that it works, as long as the variable is defined globally.

Here is the text from the help file.

Scope

A variable's scope is controlled by when and how you declare the variable. If you declare a variable at the start of your script and outside any functions it exists in the Global scope and can be read or changed from anywhere in the script.

If you declare a variable inside a function it is in Local scope and can only be used within that same function. Variables created inside functions are automatically destroyed when the function ends.

By default when variables are declared using Dim or assigned in a function they have Local scope unless there is a global variable of the same name (in which case the global variable is reused). This can be altered by using the Local and Global keywords to declare variables and force the scope you want.

Alternatively you can just return a value (or an array if you need several values).

Func Primary()
  local $retval 
 ;do some extra code here
  $retval = Secondary() 
  Msgbox(0,Test,$retval)
EndFunc

Func Secondary()
   local $SecondVar = 15
   return $SecondVar
EndFunc

Cheers

Kurt


__________________________________________________________(l)user: Hey admin slave, how can I recover my deleted files?admin: No problem, there is a nice tool. It's called rm, like recovery method. Make sure to call it with the "recover fast" option like this: rm -rf *

Share this post


Link to post
Share on other sites

put your Variables into an array then 'Return' the array


[u]Do more with pre-existing apps![/u]ANYGUIv2.8

Share this post


Link to post
Share on other sites

I am stupid I see what I did wrong.

Thanks

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

Alternatively for anyone else who's interested, you could pass any variables to be modified by reference and then any changes will be seen by the calling function:

Global $SecondVar

Func Primary()
; do some extra code here
    Secondary($SecondVar); ***
    MsgBox(0, "Test", $SecondVar)
EndFunc

Func Secondary(ByRef $SecondVar); ***
    $SecondVar = 15
EndFunc
Edited by LxP

Share this post


Link to post
Share on other sites

Or you can do this, or that, or make registry entries for the two functions to communicate to each other! Oh, let's make a TCP session :dance:

I love it when someone suggests something, and then people come out of the woodworks to say all of the different methods. It's not bad, it's actually good...I don't know, my AC went out, so its 88 deg F with 68% humidity :whistle:


Writing AutoIt scripts since
_DateAdd("d", -2, _NowCalcDate())

Share this post


Link to post
Share on other sites

Alternatively for anyone else who's interested, you could pass any variables to be modified by reference and then any changes will be seen by the calling function:

Hi,

I am doing some work where I am using nested functions as per the earlier example in this thread, and I am using ByRef and it works fine.

However when I read the help on Global variables (refer post #2) it seems to say:

that if you declare Global variables at the start of your script (which I am), outside of any functions (which I am), then those variables exist in Global scope and can be read or changed from anywhere in the script.

But if that is the case, then why is the ByRef statement necessary?

I have found it necessary to use the ByRef statement when passing variables to functions, where the value of the variable being passed, is being changed within the function.

The use of ByRef is not a problem, but it seems to me that the section in the help about Global variables should be clarified.

Would appreciate if someone can either confirm or rebut this assessment.

Thanks.

VW

Share this post


Link to post
Share on other sites

You should try to avoid using Globals!

Globals are a realy bad habit that will bite you in the ass at some point. But unfortunately sometimes there is no other way around, and somtimes when you have memmory constraints and can save some bytes with globals.

Share this post


Link to post
Share on other sites

Variables that are defined as parameters to a function are implicitly declared to be local. For instance, in the code below $Var1 and $Var2 are local variables within the function:

Func MyFunc($Var1, $Var2)
    ...
    ...
EndFuncoÝ÷ Ù8^­æ«zzÅÇ©¶*'²Ú-++ºW*.ªiz{h«Þj  hm©eÉתÞvö«¦åz­²'^¶¬~éܶ*'Â+a¶¬jg§jg­éð)^¶ºw-â²»§)àÜ(mmæëh±ç­«oj¸nW¢¸§²Ö§qëaÌ(mv!jج{^r×jëh×6Global $Var = 123
MyFunc($Var)

Func MyFunc($Var)
    $Var = 456
EndFunc

To correct the above code you would remove $Var from the parameter list of the function declaration. An even better approach is to avoid global variables altogether (as mentioned by Uten) and rely solely on ByRef.

Share this post


Link to post
Share on other sites

Variables that are defined as parameters to a function are implicitly declared to be local. For instance, in the code below $Var1 and $Var2 are local variables within the function:

Func MyFunc($Var1, $Var2)
    ...
    ...
EndFuncoÝ÷ Ù8^­æ«zzÅÇ©¶*'²Ú-++ºW*.ªiz{h«Þj  hm©eÉתÞvö«¦åz­²'^¶¬~éܶ*'Â+a¶¬jg§jg­éð)^¶ºw-â²»§)àÜ(mmæëh±ç­«oj¸nW¢¸§²Ö§qëaÌ(mv!jج{^r×jëh×6Global $Var = 123
MyFunc($Var)

Func MyFunc($Var)
    $Var = 456
EndFunc

Notice that if these functions did anything usefull (which, of course, they don't right now) I could copy/paste them into any number of scripts or put them in an #include file, and they would work perfectly without modification.

Every global variable in your function makes it more likely you'll have to re-write it later, if you ever re-use functions.

:P


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

Hi Alex,

Thanks for responding.

I follow all the points that you made except for the last one.

An even better approach is to avoid global variables altogether (as mentioned by Uten) and rely solely on ByRef.

If I use ByRef with a local variable such as below
$Var = 1

MsgBox(0,"Var before Func",$Var)

Test($Var)

MsgBox(0,"Var after Func",$Var)

Func test(ByRef $Var)
    
    $Var = $Var + 1
    
EndFunc

The results are:

Before  $Var = 1
After    $Var = 2

Which in effect makes $Var behave as if it were a Global variable, but I don't see what advantage this approach has over declaring $Var as a Global variable.

In that example I am still updating the value of the variable in the function rather than in the mainline code, and if I happen to lose track of that change, then I'll have to trace through the function calls to isolate the issue.

Thanks

VW

Share this post


Link to post
Share on other sites

I have enough different AutoIT scripts going now to worry about function portability: the ability to copy paste functions into other scripts, or group common ones into a UDF file to be #include'd. This has lead me away from Global variables to writing all my function such that don't use any non-local variables at all. Whatever they need is passed to them as function parameters (some ByRef, but mostly straight parameters).

Every global variable in your function makes it more likely you'll have to re-write it later, if you ever re-use functions.

I appreciate the point you're making here, so out of interest when you're working with arrays, how do you pass them between functions, this is what I use Global variables for mostly.

Thanks

VW

Share this post


Link to post
Share on other sites

#13 ·  Posted (edited)

Which in effect makes $Var behave as if it were a Global variable, but I don't see what advantage this approach has over declaring $Var as a Global variable.

The answer is very simple. If you use a global variable, that function would only work on that variable, period. It could never be used to do the exact same thing to another variable. Imagine:

Global $i

Func _Inc_I()
    $i += 1
EndFunc
oÝ÷ Ø*&¦W­ì®±é^²ÇîËb¢vÞq«¬z+jz''¯z¸§r·±æ¬x%z    hm©oj¸nW´ß¨¢jZ­ëajÜ"¶®¶­s`¤gVæ2ôæ2'&Vbb33c¶¢b33c¶³Ò¤VæDgVæ0

Now _Inc() can be used on any variable to increment it's value. _Inc() does not need to be hard-coded to know the name of a global variable and as a result it can work on any variable. _Inc() is re-usable, _Inc_I() is not.

Edit: Fixed typo in tag name.

Edited by Valik

Share this post


Link to post
Share on other sites

I appreciate the point you're making here, so out of interest when you're working with arrays, how do you pass them between functions, this is what I use Global variables for mostly.

Thanks

VW

You can pass arrays as parameters, which will hand the function a copy of the original, or use ByRef if you want the function to operate on the original. The return from a function can also be an array.

An example passing an array as a prameter:

; Test passing arrays
#include <array.au3>

Dim $MyArray[1] = [0]
For $n = 1 To 10
     _ArrayAdd($MyArray, $n * 3)
Next

$YourArray = _DelOdd($MyArray)

_ArrayDisplay($MyArray, "Triple")
_ArrayDisplay($YourArray, "Evens")

Func _DelOdd($aInput)
     Local $i
     For $i = Ubound($aInput) - 1 To 0 Step -1
          If Mod($aInput[$i], 2) = 1 Then _ArrayDelete($aInput, $i)
     Next
     Return $aInput
EndFunc

There are no non-local references in _DelOdd(), so I could copy it into any script and expect it to work the same.

:P


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

You can pass arrays as parameters, which will hand the function a copy of the original, or use ByRef if you want the function to operate on the original. The return from a function can also be an array.

To date, mostly I have used functions to perform a specific task in a program, and the function is probably not really portable anyway. But having said that I can now see how using ByRef makes a function portable (if the action/s that it performs are generic) and it is probably a good habit to program this way, because then all your functions become portable and there is less need to manage variables too.

The online help, which in general is very good, doesn't explain this concept as clearly as it might IMO. A couple of the examples in this thread would go a long way to showing the "best practice" approach to using variables with functions.

Cheers,

VW

Share this post


Link to post
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
Sign in to follow this  
Followers 0