Page 1 of 2
Variable scoping - Local variables inside loops and ifs, etc
Posted: Thu Mar 01, 2007 1:09 am
by Joakim Christiansen
I want to be able to define local variables inside loops and ifs, etc. When you define variables inside IF's or loops or whatever I want them to be protected inside there and deleted afterward. I don't know which keyword that would be best to use for this, maybe Define, Protected or something new like Local?
Like this:
Code: Select all
If DoSomeAdvancedStuffThatRequiresManyVariablesYouDontWantToBeGlobal
Local.l Variable1, Variable2=20 ;only available inside the if
For Variable1=0 To Variable2
Local.l Test1, Test2=20 ;only available inside the for-loop
Print(Variable1)
;bla bla bla
Next
EndIf
The reason I want this is because you can do stuff like this in Visual Basic and it makes the code so much cleaner and smarter! I would really love this feature!
Posted: Thu Mar 01, 2007 10:51 am
by GedB
Java has this feature, and in my experience it is more trouble than its worth.
The problem is the overhead of constantly allocating and deallocating the variables.
The result is that most programmers are careful to define their variable outside the loop.
Also, the example you give leads to headaches. Can you spot what is wrong with the following:
Code: Select all
If DoSomeAdvancedStuffThatRequiresManyVariablesYouDontWantToBeGlobal
Local.l Test1, Test2=20 ;only available inside the if
For Test1=0 To Test2
Local.l TestI, Test2=20 ;only available inside the for-loop
Print(Test1)
;bla bla bla
Next
EndIf
If you want scope, create a Procedure. Simple.
Posted: Thu Mar 01, 2007 7:06 pm
by Character
It prints only one zero or it prints 21 zero's? I'm not sure.
(If TestI and Test1 are the same... (typo?))
Posted: Thu Mar 01, 2007 7:14 pm
by dracflamloc
The overhead isn't really worth it. All you need to do really is zero out your variables at the start of the next loop, etc.
Posted: Mon Apr 02, 2007 1:24 pm
by Joakim Christiansen
dracflamloc wrote:The overhead isn't really worth it.
But if I put code like this into a procedure instead, doesn't that create some overhead too?
I think it would be nice to be able to program like this, and if you are scared because of any overhead then just don't use this feature.
Re: Variable scoping - Local variables inside loops and ifs,
Posted: Wed Apr 04, 2007 4:22 pm
by Rescator
Joakim Christiansen wrote:
Code: Select all
If DoSomeAdvancedStuffThatRequiresManyVariablesYouDontWantToBeGlobal
Local.l Variable1=0, Variable2=20 ;only available inside the if
For Variable1=0 To Variable2
Local.l Test1=0, Test2=20 ;only available inside the for-loop
Print(Variable1)
;bla bla bla
Next
EndIf
If you really must do something similar do this instead:
Code: Select all
Define.l Variable1, Variable2=20
If DoSomeAdvancedStuffThatRequiresManyVariablesYouDontWantToBeGlobal
Define.l Test1=0, Test2=20 ;only available inside the for-loop
For Variable1=0 To Variable2
Print(Variable1)
;bla bla bla
Next
EndIf
PureBasic should have no issues with this! And it seems to behave like you want it too. The benefit is that it's outside the loop so it's way faster and you avoid endless loop bugs that you'd get. (as pointed out earlier)
PPS! Make sure you use Define.l Var=0
if you just use Define.l Var it will not be set to 0 but previous value kept.
PPPS! Define do not make them global, they do however stick around in the "main" code, so reusing them may be smart. (saves a few bytes here and there) PB do not have a main() as C tend to do, PB's main is well, anything in the main code body. (aka not in procedures)
Posted: Wed Apr 04, 2007 4:56 pm
by Kaeru Gaman
what would that mean...
should I declare a dozen variables shared if I want to access them within the loop?
I already read such a request somewhere else earlier, and I see no advantage in it...
like GedB said: it is more trouble than its worth.
Posted: Wed Apr 04, 2007 5:21 pm
by Rescator
Yup! I think the current way works great, if you need temporary variables this is the better way to do it.
It even works with enableexplicit
Code: Select all
EnableExplicit
Procedure test()
Protected Test1.l=0, Test2.l=20
For Test1=0 To Test2
;Debug Variable1
Next
EndProcedure
Define.l Test1=0, Test2=20
For Test1=0 To Test2
;Debug Variable1
Next
Debug Test2
test()
Define.l Test1=0, Test2=10
For Test1=0 To Test2
;Debug Variable1
Next
Debug Test2
Personally I tend to call variables like these a,b,c or n,i and similar.
Then again in the main code I always define those only once as well.
And I almost stopped fully using global variables,
now I use a structure (or several) and a single global variable. (call me weird) PS! Is that more stack friendly? (looks the at PB gurus)
Posted: Wed Apr 04, 2007 5:23 pm
by ts-soft
A Userdefined Scope for Variables and Procedures is a nice idea, but not in this way
Posted: Wed Apr 04, 2007 7:25 pm
by Demivec
ts-soft wrote:A Userdefined Scope for Variables and Procedures is a nice idea, but not in this way
Maybe something like this:
Code: Select all
Define.l Variable1=0,Test1=4,Test2=2
;blah blah
BeginDefine.s Test1l="hello"
If Variable1=Test2
BeginDefine.l Test2=test()
If Test2>Len(Test1)
Debug Variable1
Endif
EndDefine Test2
Endif
EndDefine Test1
You really only need to mark the boundaries of when something is defined or not, in a procedure you might use an UnDefine command. The only use I can see in doing this is for giving "single use" variables meaningful names, instead of using them over and over for different things and giving them a generic name. An example would be:
Code: Select all
Result.l=test(5)
Debug Result
Result.l=windowID(0)
Debug Result
;or alternatively
BeginDefine.l Checksum=test(5)
Debug Checksum
EndDefine Checksum
BeginDefine.l LastWindowID=windowID(0)
Debug LastWindowID
EndDefine LastWindowID
A command to "alias" the variable would also be a solution to this scenario.
Posted: Wed Apr 04, 2007 7:37 pm
by ts-soft
My idea is like this:
Code: Select all
Global Hello.l
Procedure Foo()
; some code
EndProcedure
; ##############
BeginScope
Global Hello2.l ; only in this Scope global
Procedure Foo2() ; only in this Scopa available
; some code
EndProcedure
EndScope
; ##################################
; Hello global, Foo() avalaible
; Hello2 not defined, Foo2() not available
Posted: Thu Apr 05, 2007 6:21 pm
by Demivec
@ts-soft:
Your idea seems like it would share somethings in common with a VB6 Module like feature.
Posted: Thu Apr 05, 2007 6:32 pm
by ts-soft
Demivec wrote:@ts-soft:
Your idea seems like it would share somethings in common with a VB6 Module like feature.
Yes
Is good for oop with priv. Procedures as Methods and so on
Posted: Fri Apr 06, 2007 8:08 pm
by Dr. Dri
Maybe a Block/EndBlock keyword ?
Dri
Posted: Sat Apr 07, 2007 2:51 am
by Dummy
Demivec wrote:A command to "alias" the variable would also be a solution to this scenario.
There's already a solution for your "alias":
Code: Select all
Macro Line
Command
EndMacro
Procedure DoSomethingImportant()
Protected Command.s
For i = 0 to count ; loop 1
Command = ProgramParameter()
; ...
Next
For i = 0 to 10 ; loop 2
Line = ReadString(1)
; ...
Next
EndProcedure
It's ugly, I know...
In this example the variable "Command.s" from loop 1 is reused as "Line.s" in loop 2.
Now there are two questions:
1. Why do I reuse that variable instead of declaring another one?
Imagine a Procedure that is called more often, maybe even recursive, and imagine there'd be 10 or 20 such loops - it would lead to a lot of memory beeing wasted or in the worst case even to a stack overflow.
2. Why don't I simply call that Variable String1?
Because I want my code to be readable!
PS and BTW:
A nice solution would be:
Code: Select all
Procedure DoSomethingImportant()
Protected Command.s Alias Line.s Alias String.s Alias ...
For i = 0 to count ; loop 1
Command = ProgramParameter()
; ...
Next
For i = 0 to 10 ; loop 2
Line = ReadString(1)
; ...
Next
For i = 0 to 10000 ; loop 3
String = Mid(...)
; ...
Next
EndProcedure
or:
Code: Select all
Procedure DoSomethingImportant()
Protected String1
Alias String1 As Command
For i = 0 to count ; loop 1
Command = ProgramParameter()
; ...
Next
Alias String1 As Line
For i = 0 to 10 ; loop 2
Line = ReadString(1)
; ...
Next
Alias String1 As String
For i = 0 to 10000 ; loop 3
String = Mid(...)
; ...
Next
EndProcedure
or maybe even this:
Code: Select all
Procedure DoSomethingImportant()
Protected String1
Alias String1 As Command
For i = 0 to count ; loop 1
Command = ProgramParameter()
; ...
Next
RemoveAlias Command
Alias String1 As Line
For i = 0 to 10 ; loop 2
Line = ReadString(1)
; ...
Next
RemoveAlias Line
Alias String1 As String
For i = 0 to 10000 ; loop 3
String = Mid(...)
; ...
Next
RemoveAlias String
EndProcedure