Object Oriented Function Pointers?

BlitzMax Forums/BlitzMax Beginners Area/Object Oriented Function Pointers?

Gabriel(Posted 2005) [#1]
I can't find any reference to function pointers anywhere in the docs, but I'm sure we have them. I'd like to get them competely encapsulated within an object though. I'm not sure this is even possible but it sure would be nice.

Let's say my object is a GUI Buttono of some kind. It has a Method called Action() which is called whenever the button is clicked. Now I'd like to be able to change that action to anything else in the game, including standard functions, functions of the same object or a different object and methods of the same object or a different object.

The GUI Object has a method called SetTarget() which is where I'd like to set what the object does when Action() is triggered.

So Something like this ( pseudo code )

Button1=CreateButton()
Button2=CreateButton()
Button2.Hide()
Button1.SetTarget(Button2.Show())

Then when I click on Button 1, Button 1's Action() method is triggered, which by now points to Button 2's Show() method and button 2 is unhidden.

As I say, it need not always be a method of the same type and it might just be a function, so hopefully it's possible to do it each way?

Possible?


CoderLaureate(Posted 2005) [#2]
I'd like to know this too.

Guess the best way to find out is just to experiment. I know you can set a pointer inside of an object to a function outside of the object. I don't know about 'Method Pointers' though.

When setting up a function pointer you have to make sure the signatures match:

*this code is untested, I just put it there to show how to use the function pointers.*

Type foo
   'Declare Function Pointer
   'This can be any name, I just chose the text 'FunctionPointer'
   'for demonstration purposes.
   Field FunctionPointer(Sender:foo)
   Field Name$
   Field Age
   Function Create:foo(Name$, Age)
      Local f:foo = new foo
      f.Name = Name; f.Age = Age
      return f
   End Function
   Method Update()
      'Check if the function pointer has been assigned.
      If FunctionPointer <> null Then 
          'If so, call the function and pass the parameters
          FunctionPointer(Self)
      End If
      Print "Name: " + Name
      Print "Age: " + Age
   End Method
End Type

Function FooFunction(Sender:foo)
   'Sender refers to the current foo object that's
   'calling this function.
   Sender.Age:+25
End Function

Local f:foo = foo.Create("Jim",39)
f.FunctionPointer = FooFunction

f.Update()

Should print:
Name:  Jim
Age:  64



Hope this helps.


ImaginaryHuman(Posted 2005) [#3]
There is currently no such thing as a method pointer and no way to access it.

To create a function pointer you define it as a dummy function:

Local myfunctionpointer()

Then you can treat it like a variable, although it mainly only can interact with other function pointers. All functions that you actually create in your program have a function pointer - which is the name of the function. For example:

Function myfunction()
print "yes, by Jesus!"
End Function

There is now a function pointer in existence called myfunction.

So you can create a dummy function pointer and then make it point to any other existing function at your leisure, for example:

Local myfunctionpointer()

Function myfirstfunction()
print "one is where it all starts!"
End Function

Function mysecondfunction()
print "two makes for a good game!"
End Function

myfunctionpointer=myfirstfunction 'WITHOUT THE ()!
myfunctionpointer() 'CALLS THE `FIRST` FUNCTION!

myfunctionpointer=mysecondfunction 'WITHOUT THE ()!
myfunctionpointer() 'CALLS THE `SECOND` FUNCTION!

myfunctionpointer=myfirstfunction 'WITHOUT THE ()!
myfunctionpointer() 'CALLS THE FIRST ONE AGAIN.

You can I think change a function pointer into a byte pointer with Byte Ptr(myfunctionpointer), but that is the only translation allowed. If you want an Int pointer it has to be Int Ptr(Byte Ptr(myfunctionpointer)).

To assign a function to a function pointer, refer to the function you want to use without the `()` on the end, otherwise the function would actually be called.

To call the function assigned to your function pointer, just use your function pointer as if it's calling that function ie myfunctionpointer().

You can set up parameters for your functions. If you create a function that you want to use and it has an Int and a Float as the parameters, you also must define your function pointer variable with the same parameters. They must map onto the same params and variable types! e.g.

Function actualfunction(Param1:Int,Param2:Float)
Print "doing stuff"
End Function

Local myfunctionpointer(Thing:Int,Thing2:Float)
myfunctionpointer=actualfunction
myfunctionpointer(15, 25.934)

You can get the function pointer of a function that is defined within a custom Type, but you can't get the function pointer of a Method. Also you will notice if you manage to print out the function pointer, that there is only one instance of a `function within a type` that is shared amongst all instances of that type. The memory address is the same as used by all instances, even though it appears that each instance has its own function.

If you get some problem whereby it seems like the function is actually called rather than just returning the function pointer, make sure you don't use the () on the end and make sure to simplify the operation on its own line with no other fancy combinations of operations at once. Just do myfunctionpointer=realfunctionpointer on a line by itself, so as not to confuse things.

You can create an instance of a type at runtime, and then equate the function pointer of one of its functions to your own function pointer variable declared elsewhere. However, again, all instances of that type share the same actual function, so there is no way to create custom functions at runtime. Believe my I tried! ;-)

I hope this helps. I think that about covers it.


Gabriel(Posted 2005) [#4]
Thank you both for the information. That all makes sense now.

If the function address of a type instance returns the same address, that would explain why method pointers are out. It's not unreasonable to expect this though, is it? I mean, I'm not an experienced C++ programmer, but I understood that C++ supports method pointers, along with Delphi and Java.

It's messy having to go outside of the object to do things.


Dreamora(Posted 2005) [#5]
C++ is no language to compare as it has no managed and type safe system.

But some kind of method pointer would be nice, thats right ...
The only reason I could see that they should not work might be that the memory manager of BM moves around type instances which would break method pointers ...

Perhaps we will see that somewhen later ...


ImaginaryHuman(Posted 2005) [#6]
Yes, the reason the function pointer for a function within a type is the same, is that it creates one function for the `type`, not for the instances. You reference it with mytype.function() rather than something like myinstance.function(). They all share the same function.

Thing is, even if you had a method pointer, there probably also would only be one method for the type shared amongst all the instances of the type. Otherwise, to have an actual piece of machine code for every type instance, you'd have to be able to move chunks of code around at runtime, relocate them, reassign any changes in for example the address of labels, get the cache flushed out so that it can be executed, etc... plus what Dreamora said about the pointers moving and not being kept consistent. I'm sure there's other issues too. It would be cool though.


Gabriel(Posted 2005) [#7]
I understand that, but that's because you only pass the address of the function. From what I've read, languages which support proper method pointers ( per instance ) do so by passing *two* 32 bit ints, one for the address of the function and one for the instance. You still only have one function, it's just that the instance address gets passed too.