Declaring Local and Global in a function

BlitzMax Forums/BlitzMax Programming/Declaring Local and Global in a function

Grey Alien(Posted 2006) [#1]
Take this example:

Strict
Do()

Function DO()
	Global x
	Do2()
	Print x
	
	Function Do2()
		x:+1
	End Function
End Function


If I declare x as local, it won't compile as the x in Do2() won't be recognised. However, does it make much different to speed if x is declared as global *in a function* and then used a lot? I appreciate that if x was declared global *outside of the function* i.e. global to the whole app, it would be held in memory and not a CPU register and thus a lot slower.

Also what happens when the app runs out of registers in a function (due to a lot of local vars), does it push and pop using a stack and is this the same speed as storing/retrieving from memory or does the CPU cache it somehow?

Any techie answers appreciated...


Curtastic(Posted 2006) [#2]
I believe functions inside functions are messed up. I would like them to be supported.

But this:
Function DO()
	Global x[9]
EndFunction


is faster than this becuase the array doesn't need to be reallocated every time.
Function DO()
	Local x[9]
EndFunction



Grey Alien(Posted 2006) [#3]
messed up hey, that could explain a bug I just posted in the bug forum.

So global in a function means it's not reallocated each time, hmm dodgy but worth knowing. What about if it was a Type and not an array?


Dreamora(Posted 2006) [#4]
does not change anything. Global within function means static -> no reallocation after first init.


H&K(Posted 2006) [#5]
Wasnt it posted somewhere that the bug was that the compiler didnt throw an error when you tried to declare a function within a function

ie You're not allowed to do it, but it doesnt tell you so yet


Dreamora(Posted 2006) [#6]
Function within a Function is a valid construct in BM.
Even BRL core modules use that and I use it very often for local functions that I otherwise would inline etc.

The only thing you have to take care of is that even a function within a function is its own variable space and only knows of application / module globals and stuff it was given on calling.


Grey Alien(Posted 2006) [#7]
Function within a Function is a valid construct in BM.
Absolutely, the code I posted at the top works fine. It's a very useful facility to avoid huge amounts of inlining in some cases.

The only thing you have to take care of is that even a function within a function is its own variable space and only knows of application / module globals and stuff it was given on calling.
AND as I proved above it knows of globals within the parent function, but not locals within the parent function.


Dreamora(Posted 2006) [#8]
jupp, and parent function globals which makes sense as they are global to that scope.

Locals is the same with base app and functions btw. Functions called from "base app" don't know of locals defined in the base app.


(tu) ENAY(Posted 2006) [#9]
Hmm, I didn't realise you could declare globals inside a function. That's quite unusuaul.

Has anyone else noticed you can create 'Const' variables inside a type that aren't global? I wonder if they're created for each instance for a type or are simply just replaced as numbers because you can't access them globally outside the type.

PS Grey Alien, NEVER make a function inside a function, that is just plain wrong :)


Dreamora(Posted 2006) [#10]
Const exist on type level as globals do.
And you can access them globally outside, many here use that approach to fake enumeration.

type TEnum
  const up:int = 100
  const left:int = 100
end Type

print TEnum.up + "," + TEnum.left



Grey Alien(Posted 2006) [#11]
ENAY: Functions inside Functions are vital as we've said so you can avoid typing the same piece of code multiple times. I use them all the time in Delphi data handling routines.


sswift(Posted 2006) [#12]
grey:
Global in a function means if you set X to some value, the next time you enter the function, X will still have that value you set.

It should be accessable to that function inside the function. But it's not, for whatever reason, either because of a bug or because functions in functions aren't fully supported.

Enay:
"Hmm, I didn't realise you could declare globals inside a function. That's quite unusuaul."

They're not accessable from outside the function if you were wondering that. They're just like static vars in C. I'm not sure why Mark chose to use the term Global. That doesn't really indicate the nature of them not being freed when the function exits. And if they're not accessable within functions in a function then function globals are even less like regular globals.


Grey Alien(Posted 2006) [#13]
swift: OK I get it, the global is persistant. btw, you *CAN* access the global in the function inside the function, that was the point of the post (my code example above works you see) and to find out how slow globals were compared to locals when the globals are declared in a function instead of in the main app.


sswift(Posted 2006) [#14]
Oh I thought you were saying it didn't work. I must have read global when you wrote local.


Grey Alien(Posted 2006) [#15]
well you leant something wrong and have now unlearned it, so that's OK :-)


SoggyP(Posted 2006) [#16]
Hello.

Grey, oh ye inna tutu, you mentioned above that there's a speed hit using the global vs local declaration. What kind of impact are we talking here - mayfly pee on the ocean or fat bugger off the top diving board?

Goodbye.


Grey Alien(Posted 2006) [#17]
well it's simply that the CPU has "registers" which can store say a loop variable and other local variables (only a limited number) and it can access them way quicker than variables stored in RAM. I was trying to figure out if modern CPUs have a quick way of transfering stuff from the registers (when they get full and a new variable is needed) to the stack (temp area of ram for variables). Hey surely you know all this anyway right?


Dreamora(Posted 2006) [#18]
Isn't the CPU cache used before the RAM? And today systems have 2MB of Cache ... which theoretically should be more than enough for "regular stuff" :-) (I know 4 apps that are able to "overfill" my cache, 2 of them are cpu overclocking stability testapps ^^)


Grey Alien(Posted 2006) [#19]
yeah you are probably right, I suppose there's special CPU commands for using a stack in the cache as well instead of reading from RAM = slow.


tonyg(Posted 2006) [#20]
So, what kind of impact does the use of locals vs globals have?


H&K(Posted 2006) [#21]
Sometimes none, but it does make a difference. Its one of theose things that you either do all the time or dont, so you dont realy notice.

For example I used to "Global Loop" and then use that for all my for loops in the program, now, (Thanks to anther thread like this), I would "For Local Loop", I dont notice the difference obviously, but my understanding is that over the long run it will


Dreamora(Posted 2006) [#22]
globals have a little slower access time, which might make a difference for some stuff and not for other things. Its never an intelligent idea to use "calculation variables" of type int / float globals if you perform math operations on them, as this is the situation with the worst impact.


Hotcakes(Posted 2006) [#23]
what kind of impact does the use of locals vs globals have?

As has been said, Ram usage vs internal CPU caches and registers... In B3D/B+, all variables (Local or Global) were stored in RAM.

Max is much smarter in that it will store as many Local variables in the CPU registers as possible... which means Global variables are the same speed as they have always been, but Local variables are the fastest a variable can possibly be.


tonyg(Posted 2006) [#24]
Has anybody got code which will show the difference between using globals vs locals?


Dreamora(Posted 2006) [#25]
Core Duo T2500

Time needed for global ops: 2491
Time needed for local ops: 1412

SuperStrict

Global gFloat:Float = 1.25

Delay 500
Print "Time needed for global ops: " + gFloatF()
Delay 500
Print "Time needed for local ops: " + lFloatF()

End 

Function gFloatF:Int()
	
	Local t1:Int = MilliSecs()
	For Local i:Int = 1 To 10000000
		gFloat :* gFloat
	Next
	t1 = MilliSecs() - t1
	Return t1
End Function

Function lFloatF:Int()
	Local lFloat:Float	= 1.25
	Local t2:Int = MilliSecs()
	For Local i:Int = 1 To 10000000
		lFloat :* lFloat
	Next
	t2 = MilliSecs() - t2
	Return t2
End Function


EDIT: Reordered the code to look cleaner and perhaps make more sense.


tonyg(Posted 2006) [#26]
<edit> Actually, I don't see.
If you take out the function global gfloat assignment the difference isn't much... or have I missed something?
<ano-edit> Still getting very similar results for each. Could it be machine specific differences? I'm using PIII laptop with S3


Dreamora(Posted 2006) [#27]
I reordered the code.
Yes potentially you are right.

main problem is that there isn't enough stuff going on to really compare those 2 because unless there is enough stuff to handle, BM does not seem to push globals to RAM (ie as long as local and global fit in cache, it seems like BM or my CPU is doing this)


H&K(Posted 2006) [#28]
Also, Ive said this before, but no one ever pays any attention to it, If you allocate them wrong you actualy make variables slower than B3d


tonyg(Posted 2006) [#29]
Sorry if you've been ignored H&K. Have you got any code that shows what you mean?
How do you mean 'allocate them wrong'?


H&K(Posted 2006) [#30]
http://www.blitzbasic.com/Community/posts.php?topic=59361#661382

But any way tony have you read this
you should NOT be able to call a method from within a function
Its from the copy thread of this one that grey posted in the bug section
http://www.blitzbasic.com/Community/posts.php?topic=63020

That must be a mistake mustnt it?


tonyg(Posted 2006) [#31]
Yep, I nearly posted a response. I *think* Mark means you should *not* be able to call a method from a function within a method as there is no 'self'.
<edit> to add the all important 'not'.


Grey Alien(Posted 2006) [#32]
H&K, I think he meant in a specific situation (i.e. no Type prefix before the method), not the way you are using them.


H&K(Posted 2006) [#33]
Ok lets say he ment that, and I allocal a global inside the method
Strict

Global Grid[10,10]

Type TA
	Method do()
	GLobal Temp:Ta = self
		do2()
		
		Function do2()
			Local G=Grid[0,0]
			Temp.do3()
		End Function
	End Method 
	
	Method do3()
		Print "OK"
	End Method 
EndType

Global A:TA = New TA
A.do()

Now this works yes?

But mark said "Woops, it's a compiler bug - you should NOT be able to call a method from within a function!"

Which seems very over the top when all grey needed to to was create one little global.

I agree with what you have both posted, but until mark or skid says that the post was in error we cannot be sure


H&K(Posted 2006) [#34]
Double post


Dreamora(Posted 2006) [#35]
H&K: No its no error.
A function exists only on type level. A method only on instance level. So if you want to call a method from a function, you must give the type instance to the function as well (Event Handlers work that way for example) so the function then can use this type instance to execute the method on it.

I've never even tried to call a method from function ... didn't make much sense as a function does not know where it was called from or should (as mark said, its a bug)


H&K(Posted 2006) [#36]
Dream, I think you are wrong. I think Mark madde a mistake. If you look I ave made Greys code work just by letting the fuction know what "Self" is

"Woops, it's a compiler bug - you should NOT be able to call a method from within a function! "

Is simply either not true, or somthing we should worry about


Dreamora(Posted 2006) [#37]
Nope definitely not.
Functions are clearly declared as beeing NOT instance bound. But a method needs to be executed on an instance -> function has no self so calling a method is called on null which normally should result in "can't be called on null" error.

If you need something thats executed on an instance, use a method. if you want it to be calleable as SomeType.Function then use a function but that one does not know what an instance of type it has to use unless you specify it.

If the compiler would react correctly, doing something like

someTypeInstance.SomeFunction would result in an error that there is no method with that name.


H&K(Posted 2006) [#38]
I know they are not instance bound. Please stop trying to tell me what you know, and tell me why you should NOT be able to call a method from within a function.

Look at the change Ive made to Greys code, the Function now knows about self, and calls a method. So it works. So why Is mark telling me that its a compiler error?

Im not even saying I would do this, Im just saying if all I need to do was let the function know which instace it is to work on, why has mark said "Woops, it's a compiler bug - you should NOT be able to call a method from within a function!"


Dreamora(Posted 2006) [#39]
What mark means is that this is a bug:

Type TTest
   field name:String

   method myName:string()
      return name
   end method

   function Test()
      print myName()
   end function
end Type

local test:TTest = new TTest
test.Test()


Reason: Function has no self, so calling myName is done on Null which logically can't work, but currently does due to a compiler error.
The correct code that is not bugged would look like this:


Type TTest
   field name:String

   method myName:string()
      return name
   end method

   function Test(obj:TTest)
      print obj.myName()
   end function
end Type

local test:TTest = new TTest
TTest.Test(test)


Currently you could even use:

test.Test(test) instead of TTest. But I think such a usage (function on type instance) is extremely missleading and confusing.


H&K(Posted 2006) [#40]
@Dream,

I Also know what I think Mark ment

BUT he said this

Woops, it's a compiler bug - you should NOT be able to call a method from within a function!

So telling me "No its no error." Is wrong.

Stop right now, dont post with another example. Is marks statement right or wrong. Dont try and decide what he ment just look at what he said.


Dreamora(Posted 2006) [#41]
His statement is right.
The way greys code (which does it similar as example 1) called the method is a compiler bug.

And thats exactly what he said, as he answered Grey's posting with that code.


H&K(Posted 2006) [#42]
Woops, it's a compiler bug - you should NOT be able to call a method from within a function!


So eventhough I have made Greys code work. You think that the compiler should tell me that I CANNOT call a method from within a function?

Strict

Global Grid[10,10]

Type TA
	Method do()
	GLobal Temp:Ta = self
		do2()
		
		Function do2()
			Local G=Grid[0,0]
			Temp.do3()
		End Function
	End Method 
	
	Method do3()
		Print "OK"
	End Method 
EndType

Global A:TA = New TA
A.do()

Before you post "but he ment....." ALL my post have been to mark to clarify what he ment, and you posting is not doing that.

If it was a mistake (Which I think it was), then mark needs to say so. If he really is going to change the compiler so that you cannot call method from within a function then he needs to say so.


Dreamora(Posted 2006) [#43]
The problem is it was a mistake, but the compiler didn't catch it and even worked.
I think what mark meant with its "woops that a compiler error" was that the compiler shouldn't have been able to call do3 from within the function without a specified instance. Normally if no instance is specified, self is used, but as we all know, a function has no self and thus a "tried to call Do3 on null" error should appear but the compiler currently seems to accept the calling object instance as self even on functions.
So that would be a compiler bug.

I thought it would be quite obvious what compiler error he meant as there was a quite obvious one in that code (function calling method without an existing object without getting a compiler error)


H&K(Posted 2006) [#44]
So right at the very start of this exchange why did you say that I was wrong in thinking mark had said the wrong thing?
You are now saying "what mark meant"

Can you not see that its not a problem or either you or I being able to program correctly but that the statment

"Woops, it's a compiler bug - you should NOT be able to call a method from within a function!" Is very definitive. Mark made a misstake in this statment. Thats it full stop. All you have posted since then has been all the things that we also thought he ment to say. All I wanted, and still want is for Mark to clarify that it was an error, or to state thit it isnt an error and that the compiler will be changed to stop Method calls from within a Function.

You have made the statment that Woops, it's a compiler bug - you should NOT be able to call a method from within a function! is not an error, becuase he MENT to say..... Thats politic speak.

Go back through your posts and see how every time you have said, no it wasnt a mistake he ment to say.... And then look at my posts where I also say I think he ment something else, yet your first statment to me was that I was wrong to assume he ment something else.


Grey Alien(Posted 2006) [#45]
stop warring.

It's all about context. I understand what Mark meant in that context. There's no point mega deconstructing it, wait until Mark gets up again (he's probably asleep right now.)

********
However, I think that, within a type, a Function and a sub-function should *NOT* be treated the same. Sure you shouldn't be able to call a method from a Type's Function because self doesn't exist, unless you do AType.Method() of course. HOWEVER, if a sub-function is inside a method, treating it like a normal type function totally limits it's usefulness as an inlining tool. It's already inside a method, so banning the sub-function from calling other methods where self is implicit seems unneccessary. I hope that as a result of this finding the langauge can be expanded not limited :-)
********

I'll post the same in the other thread.


tonyg(Posted 2006) [#46]
There's no point mega deconstructing it,

However, I think that


Classic :)


Grey Alien(Posted 2006) [#47]
haha :-) I wasn't deconstructing what Mark said (like the others), just what I thought would be nice about how it could work in the future.


Fabian.(Posted 2006) [#48]
Hi,

This topic's first post shows:
Strict
Do()

Function DO()
	Global x
	Do2()
	Print x
	
	Function Do2()
		x:+1
	End Function
End Function
If I declare x as local, it won't compile as the x in Do2() won't be recognised.
Imagine this:
'code

Function F1 ( )
  Local L
  'code

  Function F2 ( )
    'code
  EndFunction
EndFunction
Imagine your main programme calls F1 and F1 calls F1 a second time, so L exists twice, one time for each instance of F1. And if now F2 get's called it doesn't know which L to use, that's why this is simply impossible.

It depends on how the variable's are stored in memory:
Globals are stored at a constant position in the process's memory, so each function instance can access them; locals in contrast are stored on the stack, that means every function instance only knows the position of its own locals, there's no way to get the locals of other function instances.

You could work around this by using a global to store the position of the local, so if F1 gets called you store the position of the local in the global: "globalvar=varptr localvar" and inside F2 you can access to it using: "globalvar[0]"
Another way to do this would be that you pass the local variable as "by reference" variable to the sub function.

This problem isn't compiler specific, it's just a question about how the stack actually works.


H&K(Posted 2006) [#49]
F2 get's called it doesn't know which L to use


But F2 can only be called from F1, and so it uses the instance of L attatched to the F1 that called it. If we had gosub Grey could use that, and the problem you have just mentioned wouldnt exist, so why should it exist with functions?


Grey Alien(Posted 2006) [#50]
Fabian, yeah I see what you are saying but I'm saying (like H&K) because F2 is in F1 it's a shame it can't just use the L from within it's F1, or rather that the function just gets inlined instead, perhaps it needs a different keyword line Inline and End Inline...


Fabian.(Posted 2006) [#51]
But F2 can only be called from F1
I know it really looks like this but the problem is that the user can hack around this and call the function from anywhere in the code.
It's because functions are also glabal (stored at a constant position), so you could make a global variable store the function's address and then call the function from everywhere:
Global F3 ( )
F1
F3

Function F1 ( )
  F3 = F2

  Function F2 ( )
    'Do anything
  EndFunction
EndFunction
The problem is that the only thing which is actually only accessable from F1 is the symbol F2, the function itself in contrast is accessable from everywhere.
I know it would be nice to have it, I'd use it, too, but it's not possible, locals are only accessable from the function they belong to, except you do something like passing the variable's address to sub functions -> by reference parameters.
perhaps it needs a different keyword line Inline and End Inline
Yes this would be a solution...


Grey Alien(Posted 2006) [#52]
global variable store the function's address and then call the function from everywhere
aha I see, yes. Yeah some new keywords would be cool.


H&K(Posted 2006) [#53]
Gosub could solve it


Dreamora(Posted 2006) [#54]
Goto does not work with Strict / SuperStrict. It seems to be in for compatibility with old blitz as many non-strict things are (that don't work the same way with strict / superstrict)

Labels within Strict only serve 2 purposes:
- DefData statements
- Loop labels for Continue looplabel / Exit looplabel


H&K(Posted 2006) [#55]
@Dream Thats nice.

Anyway
Gosub could solve this