How to call an object inside a function? Example: The pencil object is inside a function, and after closing it, I have to use
pencil:removeEventListener ("touch", moveLapis)
How do I do that?
For when I call it normally, an error saying that the pencil is nil
You can't. Objects inside functions can only be called inside that scope, to be able to call it from outside, you would have to move your pencil object to outside the function, or add a reference outside the function to it.
For example:
local pencil
local function myFunction()
pencil = newPencil()
end
if pencil then
pencil:removeEventListener ("touch", moveLapis)
end
Of course, you would have to check if pencil has a value or some kind of verification before calling the function, to avoid an error.
Related
I'm relatively new to Delphi, so please pardon my ignorance.
As an exercise, I am writing a little MasterMind game. The idea is that, when the user derives the correct number, a custom method (Congrats) executes.
One of the options in this method is to play again. The obvious step following this is that the form must be reset to its default ("start up") state. I have created a type method for that (Resetform, declared as a method in public, as it needs to access the controls). I can't call that from Congrats, but I noticed that I can call it from other event handlers.
Is it possible to do this, and if so, how do I go about it?
Works from event handler, but not from custom procedure.
The method Resetform is a method of your form, which is why you can call it from event handler of your form, they reside in the same object.
To call your Resetform from outside the context of your form, you need a reference to your form, otherwise the code won't know which instance of your form it needs to call Resetform on.
Now, assuming you call Congrats from your form, you could add a parameter and call it like this:
Congrats(Self)
And your procedure could be implemented as
procedure Congrats(AForm : TMyForm); // "TMyForm" being the class of your form
begin
...
AForm.Resetform;
end;
But then, you could as well make Congrats a method of your form instead.
If Congrats is not called from your form, then you will need to find another way to pass your form's reference to the function, or use another approach.
I have a third party API that has an event listener adding function which takes as parameter a callback function to be triggered when the event occurs. I would like to pass argument to that callback function. I'm looking for Lua's equivalent of JavaScript's bind.
The Lua code:
EventListenerAddingFunction(myCallbackFunction); // I want to add a param to the callback here
How I would do it in JS:
EventListenerAddingFunction(myCallbackFunction.bind({}, myParameter));
Can this be done in Lua?
No Lua doesn't have this feature, so closest I can think of would be making a closure-wrapper:
EventListenerAddingFunction(function(...) myCallbackFunction({}, myParameter, ...) end)
This passes your parameter everytime the callback is called, all other callback parameters will be passed next. If you don't know your parameters use ... (I don't know them so I used varargs), it's better if you pass exact amount of parameters.
I register callback as event handler in my game, like this:
--register event handler
EventDispatcher:register("fire", mt.onPlayerFire, self)
--this is the event handler
mt:onPlayerFire()
print("play fire")
end
--unregister event handler
EventDispachter:unregister("fire", mt.onPlayerFire, self)
When the event handler is a function in module mt, it is fine to unregister it, because I can find the same function in mt to unregister it, but when I use this form:
EventDispatcher:register("fire", function() doSomething() end, nil)
I could not unregister the event handler, because it is anonymous, so I want to add some checks in my register function to prevent anonymous function as the event handler.
I have found the Proto struct in lua source code may be helpful, but I do not know what each piece means.
https://www.lua.org/source/5.3/lobject.h.html#Proto
I could not unregister the event handler, because it is anonymouse
Every function in Lua is anonymous value. So you can't unregister not because it is anonymous but because you didn't save any reference to it.
There is no way to detect inside of EventDispatcher:register() if the passed value (of function type) is also saved elsewhere. So if you really have multiple callbacks for the same event, and you want to unregister one specific callback, then you must have a way to identify that exact callback function.
That means you should either save the function value somewhere, so its own value could be used later as identifier for unregister(), as it is now, or return new callback's instance id, generated inside of register() when callback was added. Either way, there's something to be stored outside of EventDispatcher to identify exact callback.
This kind of avoids your question a bit, but it might solve your problem nonetheless.
When registering a new callback you could simply return some sort of identifying value, like an ID, a table or even the function itself. This could allow you to unregister it at a later moment.
local firehandler = EventDispatcher:register("fire", function() do('something') end)
-- Do some stuff here...
EventDispatcher:unregister(firehandler)
The downside is that you may have to change the way your event dispatcher keeps track of its registered events, but at worst this means implementing some linked list, and at best you can just use a Lua table to keep track of your handlers.
As for detecting anonymous functions, that's not really possible. Lua doesn't distinguish a function you define in-place from one stored in a variable; it's ultimately the same thing.
It might be possible by using the debug library, by comparing the file/line where a function is defined with the call stack, but that's just inviting bugs into your code and would probably be rather slow.
I want to use a Lua API which has specific callback functions when events occur, e.g. when an TCP package arrives. At first the function have to be registered but by the functions name as a string, see the sample code below
function __init__()
local dstport = 4681
local dstIP = "192.168.1.42"
-- register the callback function
register_tcp_handler('tcp_package_handler', dstIP, dstPort)
end
-- callback function
function tcp_package_handler(srcIP, srcPort, dstIP, dstPort, payload)
-- check the payload, or reset watchdog
end
It would be nice to have other variables in callback function provided by the callee, e.g. watchdog-timer or other objects.
The most simple way I could think of is to make the extravariables global, but it is the least elegant way I reckon. Closures would be helpful if I could pass the function directly, but i can not. I have to use the functions name as a string.
Considering this mechanics, is there a more elegant way to privide variables to the callback function without making them global?
EDIT: Using closures like this
function closure_tcp_package_handler(srcIP, srcPort, dstIP, dstPort, payload, packagecounter, timerobject)
function tcp_package_handler(srcIP, srcPort, dstIP, dstPort, payload)
-- do some stuff, change packagecounter, timerobject
end
return 'tcp_package_handler'
end
and use this function twice to register, e.g. with packagecounter1, timerobject1 and packagecounter2, timerobject2, only the last pair of parameters will be changed.
You're dealing with a callback infrastructure. In which case, your code is not the one invoking the handler. As such, there's no way to hide those parameters; if you can change them, so can someone else with access to the module providing the handler.
That doesn't mean that they have to be global, of course. You could make them members of a table. You could even provide setter functions to set the parameters, if you want to make sure that they only get certain parameters.
The simple form of this is as follows:
local handler_params = {}
function tcp_package_handler(srcIP, srcPort, dstIP, dstPort)
-- check `handler_params.payload`
end
--Make `handler_params` available for outside modification
How you do that last part is entirely up to you. You could have made it a global, but if this is in a module somewhere, it'd be better to make it a member of that module's table. And again, if you want to have some control over who gets to poke at it and how, you can use setter functions:
function tcp_handler_set_payload(payload)
handler_params.payload = payload
end
This seems to be a common issue, however I have one function which seems to work, and another which does not. I get
TypeError:clicked() takes exactly one argument, two given
Where I have binded the clicked function to a Mouse Click.
However, the handler function, which is bound with protocal to the WM_DELETE_WINDOW event, seems to work fine. How are the two different? Thanks!
class GUI():
def __init__(self,root,fit_tuples):
self.fit_tuples=fit_tuples
self.root=root
self.root.title("Beam Flux Registry")
self.root.protocol("WM_DELETE_WINDOW",self.handler)
...
# Calendar Frame
cal=Calendar(LeftFrame)
cal.pack(side=TOP)
cal.bind("<Button-1>",self.clicked)
...
#Mainloop
root.mainloop()
def clicked(self):
print "%i/%i/%i"%(self.cal.selection.month,self.cal.selection.day,self.cal.selection.year)
def handler(self):
self.root.destroy()
self.root.quit()
You need to account for the Event object in the clicked() method. When you bind a widget, the function that handles the binding will receive an object with attributes about the event that fired the function (ie, for a mouse-click event, you'll receive an object with attributes for the cursor's x and y).
The other method works because protocol isn't passing any arguments to the handler.