Declaring Local and Global in a function
BlitzMax Forums/BlitzMax Programming/Declaring Local and Global in a function
| ||
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... |
| ||
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 |
| ||
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? |
| ||
does not change anything. Global within function means static -> no reallocation after first init. |
| ||
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 |
| ||
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. |
| ||
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. |
| ||
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. |
| ||
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 :) |
| ||
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 |
| ||
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. |
| ||
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. |
| ||
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. |
| ||
Oh I thought you were saying it didn't work. I must have read global when you wrote local. |
| ||
well you leant something wrong and have now unlearned it, so that's OK :-) |
| ||
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. |
| ||
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? |
| ||
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 ^^) |
| ||
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. |
| ||
So, what kind of impact does the use of locals vs globals have? |
| ||
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 |
| ||
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. |
| ||
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. |
| ||
Has anybody got code which will show the difference between using globals vs locals? |
| ||
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. |
| ||
<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 |
| ||
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) |
| ||
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 |
| ||
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'? |
| ||
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 sectionhttp://www.blitzbasic.com/Community/posts.php?topic=63020 That must be a mistake mustnt it? |
| ||
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'. |
| ||
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. |
| ||
Ok lets say he ment that, and I allocal a global inside the methodStrict 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 |
| ||
Double post |
| ||
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) |
| ||
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 |
| ||
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. |
| ||
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!" |
| ||
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. |
| ||
@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. |
| ||
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. |
| ||
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. |
| ||
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) |
| ||
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. |
| ||
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. |
| ||
There's no point mega deconstructing it, However, I think that Classic :) |
| ||
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. |
| ||
Hi, This topic's first post shows: Strict Do() Function DO() Global x Do2() Print x Function Do2() x:+1 End Function End FunctionIf I declare x as local, it won't compile as the x in Do2() won't be recognised. 'code Function F1 ( ) Local L 'code Function F2 ( ) 'code EndFunction EndFunctionImagine 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. |
| ||
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? |
| ||
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... |
| ||
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 EndFunctionThe 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... |
| ||
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. |
| ||
Gosub could solve it |
| ||
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 |
| ||
@Dream Thats nice. Anyway Gosub could solve this |