Nested Function Memory Exception

BlitzMax Forums/BlitzMax Programming/Nested Function Memory Exception

Grey Alien(Posted 2006) [#1]
Run this code:

Strict

Global Grid[10,10]

Type TA
	Method do()
	
		do2()
		
		Function do2()
			Local G=Grid[0,0]
			do3()
		End Function
	End Method 
	
	Method do3()
		Print "OK"
	End Method 
EndType

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


You get an Unhandled Exception: Unhandled Memory Exception Error when do3() is called. Happens in debug mode and non-debug mode!

This works:

Strict

Global Grid[10,10]

Type TA
	Method do()
	
		Local G=Grid[0,0]
		do3()
		
	End Method 
	
	Method do3()
		Print "OK"
	End Method 
EndType

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



Grey Alien(Posted 2006) [#2]
This also works (i.e. no types/methods):

Strict

Global Grid[10,10]

Function do()
	
	do2()
	
	Function do2()
		Local G=Grid[0,0]
		do3()
	End Function
		
End Function

Function do3()
	Print "OK"
End Function 

do()



tonyg(Posted 2006) [#3]
Strict

Global Grid[10,10]

Type TA
	Method do()
	
		do2(Self)
		
		Function do2(temp:TA)
			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()


Is it because, although do2() is a function of method do{} it can't know about 'self'. If you change your code to call self.do3() you'll get error that 'self can't be used within a function'?


Grey Alien(Posted 2006) [#4]
IMPORTANT EXTRA INFO: I should have said earlier, my first example works if I remove the Local G=Grid[0,0] line. I did a lot of tests, if G is assigned to a type or an int/float it's fine, it's only if you assign it to an array! How weird is that?

That's an interesting observation about the function no being able to reference self due to it being a function and not a method, shame it doesn't just get turned into inline code (so it can use self and all the same variables) as that's the whole reason I was using it.

So basically my issue above smacks of a compiler bug of some kind. There's no reason why it shouldn't work. Shame as it's holding me back because the above example is a totally slimmed down example where in fact I need to call the function 6 times and it's a page worth of code in the function that needs to access about 8 local variables of the method, and it has to be fast because the whole thing is in a loop of some 100-200 times and I didn't want the overhead of calling a "real" function - I needed inline.


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


H&K(Posted 2006) [#6]
you should NOT be able to call a method from within a function


Method Set:TIntPair (Ax:Int=0,Ay:Int=0)

	Self.FX = Ax
	Self.Fy = Ay
	Return Self
	
End Method
'-----------------------------
Function Create:TIntPair (Ax:Int=0,Ay:Int=0)

	Return New TIntPair.Set( Ax,Ay )
	
End Function

This is my standard allocation code, and it calls a method from within a function, and it NEEDS to do so.

In fact the more I think about it, youve just made a slip of the tounge and ment to say something else havent you?
Because all your fucntions that have been added ontop of the core objects simply call a method anyway dont they?


Grey Alien(Posted 2006) [#7]
@marksibly: I see, but as the point of the sub-function in the method is that the code gets inlined as if it wasn't in a function at all really, then it should be able to call a method shouldn't it? Also it works without the G=Grid line, which is odd...

H&K, the way you've called your method within the function is entirely valid and supported because it's calling a method of a newly created object. I was calling my method but not having self or any instance of a type before it...


H&K(Posted 2006) [#8]
I agree that what ive done is valid, but the statement "Woops, it's a compiler bug - you should NOT be able to call a method from within a function! " seems very definitive.

So I just want a clarification from mark or skid that they are not going to change the compiler to stop calls to methods from functions.

As Ive said in my previous post I think Mark ment to say somthing else. (Or at the very least ment to add a cavat)


Yan(Posted 2006) [#9]
@GA - What makes you think sub-functions get inlined?


Dreamora(Posted 2006) [#10]
You still can call them from within a function but you have to specify the type instance (ie you have to send self to the function which shall then call the method as its done with Event Handlers in some modules / systems floating around for BM)


H&K(Posted 2006) [#11]
Ok dream so you agree that Woops, it's a compiler bug - you should NOT be able to call a method from within a function! is erronious?


Dreamora(Posted 2006) [#12]
Is what?

mark: This means that when this bug is fixed, calling a method within a function on a type, where no type instance is specified will result in a "tried to call method on null" error perhaps even with exception throw?
That would be great :)


H&K(Posted 2006) [#13]
An error


Grey Alien(Posted 2006) [#14]
"erroneous". Anyway ...

Yan: Well I've used them a lot in Delpi because at the top of the outer function you can declare a load of variables, and then you put your sub-functions. Then in the main function, when a sub-function is called, all the variables are accessible in the sub-function without being passed in (or having to be made global to the main function like in BMax). This is EXTREMELY useful and I assume it was being inlined as the main purpose of a sub-function is to avoid having to type the same code over and over, and to package it neatly for maintenance. I admit that I've only "assumed" that sub-functions are inlined in Bmax, when this may not be the case, sadly.

What would be great if sub-functions in BMax could use LOCAL variables in the main function i.e. not obeying standard BMax scope rules where they can only access global variables in the main function. OR there is some kind of old-style Macro facility or way to make inline code easily...


Grey Alien(Posted 2006) [#15]
It would be great if, within a type, a Function and a sub-function could *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 :-)


Grey Alien(Posted 2006) [#16]
oh so uh, has the compiler bug been fixed then as this thread has been moved from bugs?


Grey Alien(Posted 2006) [#17]
Hello BRL? So this was moved from bugs. Does that mean you've fixed it, or altered the behaviour, or maybe I just shouldn't code like that...?


Dreamora(Posted 2006) [#18]
Compiler bugfixes come with new major versions which means 1.23 or 1.24 not 1.22

And what you posted is a syntax error. The compiler bug fix will just make sure you won't be able to call any method from within a type function anymore without specifying an existing type instance which currently is broken. (the function has an existing self reference which it mustn't)

Tonyg above posted how the code should have looked like




Grey Alien(Posted 2006) [#19]
Sure I know that, I was just wondering if there was an official "OK, the compiler bug has been fixed" so we can expect it in 1.24.

Actually I just had an idea that could be cool. Allow Methods in Methods (not currently allowed, I tested it) instead of Functions in Methods, so that when the method is called, it already knows about self and can use all the local vars declared in the parent Method. Failing that, have a new command (as mentioned in the other thread) called Inline and End Inline, or Macro/End Macro (whatever) where you can make a sub function that uses the parent functions variables and that gets inlined by the compiler wherever you use it in the parent function...


Fabian.(Posted 2006) [#20]
I could imagine it wouldn't be too hard to implement functions querying their parent's stack context, by adding a hidden parameter to these functions, which is always set to ebp when it's called, so the function could access to the locals.
It would need the compiler to accept a QueryContext flag behind a function definition (like it currently accepts the NoDebug or "Win32" flag) which would cause the compiler to keep in mind that the function has an additional hidden parameter, so that any access to the parameters using dword[ebp+offset] would result in dword[ebp+offset+4] to make sure that the hidden parameter isn't accessed instead of a normal one. If now any part of code inside the functions parent function calls this function, the compiler would add a push ebp statement just before the call. If the called function now needs to access to its parent's locals it just could do something like this:
mov eax,dword[ebp+8] ;load the hidden parameter
mov ebx,dword[eax-4] ;access the first local variable
So
Strict
Framework brl.blitz

Func1

Function Func1 ( )
  Local Local1 = 5
  Local Local2 = 7
  Func2
  Return Local1

  Function Func2 ( ) QueryContext
    Func3
    Local1 :+ Local2
  EndFunction

  Function Func3 ( ) QueryContext
    Local2 :+ 3
  EndFunction
EndFunction
could be compiled to

So it would be possible to add something like Grey Alien asked for.


Dreamora(Posted 2006) [#21]
It wouldn't be hard, right.
But it would be breaking all consistency.
Methods are for instance based operations, function for "global" non object related operations. What you suggest would make type functions nearly similar to methods ... which isn't a really usefull idea as in that case the original seperation between those two would be pointless.


H&K(Posted 2006) [#22]
Ow come on, to solve this we just want GOSUB. Nice little implimentation that only alows jumps within the method/function. Then it would be the same namespace for Self. etc


Grey Alien(Posted 2006) [#23]
Fabian: that's very impressive.

H&K: Yeah just a new keyword would be fine.