Here is an example to you about why you should use Local Functions all the time:
Here is first the LOCAL version:
Code: Select all
Function Func1()
For Local n = 1 To 10
Func2()
DebugPrint("n:"..n)
Next
EndFunction
Function Func2()
For Local n = 1 To 5
/* do stuff */
Next
EndFunction
Func1()
Idea with this is, that when doing "FOR n = 1 to 2", most of time the N itself doesn't have much matter, and therefore it is usually most sensible to just name the same all the time, and common naming is to use variable "n" (=number) to make code easily readable.
For this reason it is not unusual that you might have several For N = 1 to 2 inside your code that are being executed inside each other, as in:
Code: Select all
For N = 1 to 2
For N = 1 to 2
For N = 1 to 2
Next
Next
Next
While you might not have it exactly the way I just showed, it will usually happen in practice, because you are having "FOR N = 1 to 2", and inside that loop there is call to another function, which also has "FOR N = 1 to 2", resulting in practice the above happening.
In the example Func1(), Func2() case the idea is that you are doing Func1(), that is calling Func2(), now you want to keep track of the progress for example, and therefore you debugprint(n) in the Func1(), which results in 1, 2, 3, 4... and you are able to see how the loop is progressing for example.
Using LOCAL things work nice, but, now, lets take a look at GLOBAL version:
Code: Select all
Function Func1()
For n = 1 To 10
Func2()
DebugPrint("n:"..n)
Next
EndFunction
Function Func2()
For n = 1 To 5
/* do stuff */
Next
EndFunction
Func1()
Now "FOR N = 1 to 2" are not using LOCAL variables, and therefore they are GLOBAL instead.
This results in couple of unexpected behaviors.
First is that since Debugprint(n:"..n) is done AFTER returning from Func2(), since Func2() also has a Global N, instead of N being value of 1, 2, 3... as intended, it is actually the last value that N was when returning from Func2().
Another unexpected thing is that by quick look you would then think that N should be 5 then, right? No, because idea is that each FOR loop increases the value of N by 1, and if it gets past the number 5, then it wont execute the FOR loop anymore, but continue forward.
So N is first 1, and For loop is executed, then it is 2, 3, 4, 5 and FOR loop is executed, then it becomes 6, and FOR loop is NOT executed, and continues forward from FOR loop, ending the Function and returning back to Func1().
And now value of N is 6, which can be seen when Func1() debugprint value of N out.
The next unexpected behavior that happens is that when Func1() FOR loop is now NEXT executed, value of N becomes 7, and then it goes to FUNC2() which again makes N be For 1 to 5, ending it at value 6 again, and again returns to Func1(), Debugprints value of N (=6) and again NEXT executed, N becomes 7, meaning it is in an endless loop, never getting out of that Func1 FOR loop, since everytime it returns from Func2() value of N is 6, and then NEXT execution makes it value of 7, and again executing Func2() making it again become 6.
This is an example of a bug that is very easy to get into your code when you start making bigger programs, and also hard to catch, since while this one ends into an endless loop, more likely you will just get a wrong value, like lets change the example to this (changing numbers in FOR in Funcs()):
Code: Select all
Function Func1()
For n = 1 To 5
Func2()
DebugPrint("n:"..n)
Next
EndFunction
Function Func2()
For n = 1 To 10
/* do stuff */
Next
EndFunction
Func1()
What happens now is that instead of being executed 5 times as intended, now it executes only 1 time, since Func2() makes the N become 11 (which is also completely unexpected result for N value for Func1() which is expected to at max be 5)
Endless loop is not so bad, since you notice that your software is stuck somewhere, and just find where it is stuck, but situation like this is much worse to hunt down, since you don't really know where exactly the problem was that might have resulted in a bug only much later in the code.