SOLVED What is the Proper Way of Handing the self-Context Over to a Callback Function?

TheMagician

Member
What is the current "best practice" way of handing the current self-context over into a callback function to be called at a later point from a different instance / script?

I need to save the self-context of a struct into a callback function so that it can later be called from a different script. Right now I'm simply writing self in the callback function but obviously that fails as soon as the callback is executed from the other script because then self refers to that script instead of the original struct that created the callback function.

I guess the reason for that is that "functions in GameMaker are not closures" but that's where my dodgy superficial knowledge comes into play ...
 

kburkhart84

Firehammer Games
The best way depends on how you have done things. I'm assuming that the other instance you want to actually do the callback from is will be storing the function in a variable. You can also store the id of the instance in another variable. Just send it along as an argument to the "initiating" function if that is how you are starting the process. Or you can directly set the variables instead.

An alternative is to only use methods. If you do, then pass a reference to the method. The method itself automatically includes the scope of the method, so if you have a method on an instance and then another instance receives a copy of that method, it will always be called in the scope of the original instance. I actually support either of these things in my input system where it needs callback support.
 

TheMagician

Member
Thank you for your quick and precise answer!

You can also store the id of the instance in another variable. Just send it along as an argument to the "initiating" function if that is how you are starting the process.
Just to be clear: In this case I would have to use method() when triggering the callback and then use the instance / struct id as the first parameter so that the callback function is executed in the correct context?

An alternative is to only use methods. If you do, then pass a reference to the method.
I actually am using methods so I've tried this approach and it works.

GML:
callback_method = function() { show_debug_message(self); }

other_struct.callback = callback_method;

//this preserves the "self" even if the other_struct is stored in a different instance / script.
 

kburkhart84

Firehammer Games
Just to be clear: In this case I would have to use method() when triggering the callback and then use the instance / struct id as the first parameter so that the callback function is executed in the correct context?
The method() function is more about creating methods that you want from other previously created methods or functions. As you mentioned, a method knows what it is binded to(preserving "self" as you say). The method() function can take either a previously created method or a built-in or global function and it turns it into a method with the defined "self." Note that a method can technically not have a binding(if you supply undefined as that parameter to method()), and so it would work like a global function, using whatever code is calling it to define the scope.

I actually am using methods so I've tried this approach and it works.
This works just fine. As long as you are defining these methods in this same way, you can just do it like this and never need to worry about the method() function. Functions that are declared as variables like this are already methods and so don't need the conversion.
 

TheMagician

Member
Note that a method can technically not have a binding(if you supply undefined as that parameter to method()), and so it would work like a global function, using whatever code is calling it to define the scope.
That's an interesting aspect of method() that isn't mentioned in the manual. Thanks for the clarification!
 
Last edited:

NightFrost

Member
I have done it only on a few occasions but I have sent self to other targets in an anonymous function callback and it has worked. I wrote a small test case and it seems to run as expected:
GML:
Foo = {
    Value : "You called?",
    Send : function(_Receiver){
        _Receiver.Init(function(){
            show_debug_message(self.Value);
        });
    }
}

Bar = {
    Callback: undefined,
    Init : function(_CB){
        Callback = _CB;
    },
    Return : function(){
        Callback();
    }
}

Foo.Send(Bar);
Bar.Return(); // "You called?"
 
Top