Callback function within a type

BlitzMax Forums/BlitzMax Programming/Callback function within a type

Kistjes(Posted 2008) [#1]
I often want an instance of a type to fire a message to an instance of another type at a certain moment.
I thought a Callback function could be used for that but I can't address a callback function within a type.
The example below is a completely useless piece of code but it illustrates what I want.

I have an instance of a TControl type.
This instance initialize an instance of a TProcess type. After a while the Process instance needs to tell the Control instance "I'm ready".

Ofcourse, I can make a reference to the Control instance within TProcess but then I need to know it's type when calling it. Like I show in the second example. But that requires me to make one generic type and extend all my types from that type. That's not what I prefer to do.

What's best?



Second example (use a generic type TElement):



Kistjes(Posted 2008) [#2]
This is what I came up with. Please tell me if it's clever or stupid?




tonyg(Posted 2008) [#3]
How about TProcess creating an Event when it is ready and TControl checking for Events? You can either use the Bmax events system or your own system.


Kistjes(Posted 2008) [#4]
Ahhh, events, of course. How could I forget?
I'm going to have a look at that.
Thanks


plash(Posted 2008) [#5]
Add a "Method" to reflection and fake it to direct to the type.function??


Brucey(Posted 2008) [#6]
A pretty standard way to have a callback function is to supply "userdata" with the function. This userdata is passed back when the function is called. Your userdata could be the object you want to invoke a method of.


Damien Sturdy(Posted 2008) [#7]
I don't get it- callback functions in a type don't work? We use them in Flow.

maybe what you need to do is set the callback *inside* the type too?


Kistjes(Posted 2008) [#8]
@Cygnus: can you show me a working example of how you implemented that in Flow?


Blueapples(Posted 2008) [#9]
I don't see how this could work given BM's current implementation of function pointers. A method just cannot be called without an object to call it on. Having a pointer to a method is meaningless without also having a pointer to a corresponding object that it should use as it's "self". That said, I think there should be a way to invoke a method pointer on a given object directly without using reflection, maybe an ._Invoke(method) method on the root class that handles the stack work, then invokes the method pointer you give it.


Blueapples(Posted 2008) [#10]
Oh, and a slightly cleaner, in my opinion, and probably faster way to implement this would be something like this, using SendMessage():



Note that this works because the root class defines SendMessage() for us (by default it does nothing and returns Null), therefore all classes in BlitzMax have it as a method. You can override it's behavior (as I have done in the example) to handle your own custom messages.


Kistjes(Posted 2008) [#11]
Hey Blueapples, that's a nice solution you've shown there. And a clear example as well. Thanks!

It uses the approach of my second example in my first post, but I was not (yet) aware of the SendMessage() method all objects inherit.

I think I go for this solution, although the Event version Tonyg suggested is nice and clean also. Mmmm, must... make... decision...


Blueapples(Posted 2008) [#12]
Events could work if you do not use an event loop with a select statement to process events - it gets really harry when you need all your objects to get a chance to process events in a loop. Possible (I've done it), but I don't recommend it. You could maybe instead use event hooks (see AddHook, EmitEventHook, and EmitEvent in the documentation).

Here's the thing: event hooks can't be methods either. They're just function pointers. You can use the data field of the TEvent object to store your context object, so it's close, but it still isn't a method. Your "methods" would look like this:

Type ...
Function Callback(id, data:Object, context:Object)
...
EndFunction
Endtype


So that Callback is actually a regular function, and it gets the event data sent to it.

Honestly though, try SendMessage. It's a lot cleaner and does pretty much the same thing as a hook will if you have only one object waiting for the callback/message/event (SendMessage obviously doesn't work if you want several objects to respond to the "callback"). It's there for the sort of thing you're doing.