Function Pointers and Methods

BlitzMax Forums/BlitzMax Programming/Function Pointers and Methods

Pengwin(Posted 2009) [#1]
Hi, I've been a member here for about 2 years now, so I thought it was time i posted.

I also have come up against something I was hoping to get an answer to. Is it possible for a function pointer to point to a method of a user defined type?

e.g. Is this valid?

Type NewClass
    Field fPointer()

    Method Test()
        Print "Hello"
    End Method
End Type

Local a:NewClass

a=New NewClass
a.fPointer = a.Test
a.fPointer()


I know this is a really trivial example, but I think it illustrates my question.


Warpy(Posted 2009) [#2]
Well, it doesn't compile...

I don't think so.


Htbaa(Posted 2009) [#3]
Since it doesn't compile I don't think it's possible. When you change the method to a function it does compile though. I'm not sure if it's even possible in any other OOP powered language. Perhaps it's because the method you give doesn't really point to anything. Instead, a memory address is pointing to the object. A method is useless without its object. So I think it's because of that. Since a function is static it's always accessible. If I'm wrong please correct me though.

Some stuff below that might help you on your way with callbacks. It's something I use when implementing the Factory design pattern.

Rem
bbdoc: Function callback
End Rem
Type TFunc
	'The actual function
	Field func:Object(data:Object)
	
	Rem
	bbdoc: Function to create TFunc object
	End Rem
	Function Create:TFunc(func:Object(data:Object))
		Local obj:TFunc = New TFunc
		'Assign function
		obj.func = func
		Return obj
	End Function
End Type

Type TAlliedPlane Extends TAirplaneBase
	Rem
		bbdoc: Create allied airplane
	End Rem
	Method Create:Object(settings:Object = Null)
		Super.Create(settings)
		Return Self
	End Method
	Rem
		bbdoc: Factory function
	End Rem
	Function FactoryFunc:Object(data:Object)
		Return TAlliedPlane(New TAlliedPlane.Create(data))
	End Function
End Type

Local callback:TFunc = TFunc.Create(TAlliedPlane.FactoryFunc)


I haven't posted the code of my TFactory type because it's not really needed here. Anyway, this should show you the, kind of wicked, syntax to accept a function pointer with parameters: Function Create:TFunc(func:Object(data:Object))


Gabriel(Posted 2009) [#4]
No, method pointers aren't valid. They're not valid because methods - at least in BlitzMax - are just functions with a default first parameter which is the instance of the type. A pointer is just a memory address so there's nowhere to store the parameter.

So no, that's not valid. But this is:

Type NewClass
    Field fPointer(C:NewClass)

    Function Test(C:NewClass)
        Print "Hello"
    End Function

End Type

Local a:NewClass

a=New NewClass
a.fPointer = a.Test
a.fPointer(a)




grable(Posted 2009) [#5]
You can of course hack your way around this, just for some fun ;)

test.bmx
Type TTest
	Field Name:String

	Method Message()
		WriteStdout "Hello " + Name + "!~n"
	EndMethod
EndType

run.bmx
Import "Test.bmx"

Extern "c"
	Function Test_Message( this:Byte Ptr) = "_bb_TTest_Message"
EndExtern

Local t:TTest = New TTest
t.Name = "World"
Test_Message Byte Ptr(t) - 8

The reference to a "method" must reside in another unit then the type that has it, or you will get duplicate symbols.


plash(Posted 2009) [#6]

Function Toggle\_Sigma()


Very strange.. looks fine in Preview though.


marksibly(Posted 2009) [#7]
Test\_test\_test

Test\_test\_test



marksibly(Posted 2009) [#8]
Test_test_test

Test_test_test
'Comment



plash(Posted 2009) [#9]
*Claps*


ImaginaryHuman(Posted 2009) [#10]
If you're going to call upon a method using a `fixed` function name, how does it associate with a specific instance of that custom type? How does it know to reference a particular field in a particular instance?


Pengwin(Posted 2009) [#11]
Thanks for the replies guys. I knew what I wrote didn't compile, I thought that maybe I had missed something.


grable(Posted 2009) [#12]
How does it know to reference a particular field in a particular instance?

It doesnt, which is why you have to pass the "this" parameter.
And the generated assembler is hardcoded to the type (it uses relative offsets from this), so passing anything other than itself or its descendants will crash eventually!


LT(Posted 2010) [#13]
I'm resurrecting this thread for a bit. Although the following...

Type NewClass
    Field fPointer(C:NewClass)

    Function Test(C:NewClass)
        Print "Hello"
    End Function

End Type

Local a:NewClass

a=New NewClass
a.fPointer = a.Test
a.fPointer(a)


...seems like a good way to go, it causes issues with garbage collection. I am working on a sprite-driven gui and am using a method similar to the above for handling mouse events. The problem is that the memory for a widget does not get entirely reclaimed if any of the internal functions have been used.

Does anyone know how to correct for this?


N(Posted 2010) [#14]
The problem is that the memory for a widget does not get entirely reclaimed if any of the internal functions have been used.
What makes you think this is happening?


LT(Posted 2010) [#15]
It is probably more accurate to say that the memory does not get reclaimed when I want it to. If I create an instance of the type and then destroy it, the memory is reclaimed. If I create the instance, then run the function, then destroy it, not all of the memory is reclaimed. I presume this is because the function takes the instance as a parameter and is not out of scope. I am looking for a way to get around that.


plash(Posted 2010) [#16]
If I create the instance, then run the function, then destroy it, not all of the memory is reclaimed. I presume this is because the function takes the instance as a parameter and is not out of scope. I am looking for a way to get around that.
That makes no sense at all. If the instance is stored no where when you toss it off to the function it should have no consequence.


LT(Posted 2010) [#17]
The instance is stored when the function is called, but then I want to get rid of the instance and end up with the same memory allocated as when I started. I apologize if I'm not explaining this very well...


LT(Posted 2010) [#18]
I have apparently misdiagnosed the problem. I created a simpler test that works fine. :(