Page 1 of 1

[SOLVED] Dynamically create methods for a class.

Posted: Sat Jun 08, 2019 11:15 am
by LeNitrous
I am trying to hook a number of love handlers to a class. All they have to do is to propagate the call to all of the children. Although there are so many handlers I decided to list them all to a table then attempt to generate them through a for loop.

The code shown below is what I described above.

Code: Select all

local callbacks = {
    "update", "keypressed", "keyreleased", "textedited", "textinput",
    "mousemoved", "mousepressed", "mousereleased", "wheelmoved",
    "gamepadaxis", "gamepadpressed", "gamepadreleased", "joystickadded",
    "joystickaxis", "joystickhat", "joystickpressed", "joystickreleased",
    "joystickremoved", "touchmoved", "touchpressed", "touchreleased"
}

for _, v in ipairs(callbacks) do
    local func = function(...)
    local args = {...}
    self.children:forEach(function(i, child)
        if type(child[v]) == "function" then
            child[v](unpack(args))
        end
    end)
end

self.class.__declaredMethods[v] = func
self.class.__instanceDict[v] = func
Is it possible in the first place? If so, what am I doing wrong?

Because this works

Code: Select all

self.update = function(dt)
    print "Hello World"
end
But this doesn't

Code: Select all

function Game:update(dt)
    print "Hello World"
end
Notes
  • I'm also using kikito's middleclass for OOP.
  • self.Children is a class similar to C#'s List.
  • Although I can use love.handlers, I decided to list only input handlers.

Re: Dynamically create methods for a class.

Posted: Sat Jun 08, 2019 12:11 pm
by grump
I'm sorry, I can't help with the middleclass stuff, just a note: This forEach construct for arrays is tempting to implement and looks clean, but be aware that it incurs a performance penalty in most cases. Callbacks like this are slower than loops and iterators in LuaJIT, and creating anonymous functions in a loop generates garbage.

Re: Dynamically create methods for a class.

Posted: Sat Jun 08, 2019 1:40 pm
by LeNitrous
I took down the forEach part. Credits to AuahDark for helping me. All I need was to change a few things around the code.

For those wondering, it's now:

Code: Select all

local callbacks = {
    "update", "keypressed", "keyreleased", "textedited", "textinput",
    "mousemoved", "mousepressed", "mousereleased", "wheelmoved",
    "gamepadaxis", "gamepadpressed", "gamepadreleased", "joystickadded",
    "joystickaxis", "joystickhat", "joystickpressed", "joystickreleased",
    "joystickremoved", "touchmoved", "touchpressed", "touchreleased"
}

for _, v in ipairs(callbacks) do
    Container[v] = function(self, ...)
        local args = {...}
        for _, child in ipairs(self.children) do
            if type(child[v]) == "function" then
                child[v](unpack(args))
            end
        end
    end
end
Container is the class.

Re: [SOLVED] Dynamically create methods for a class.

Posted: Sat Jun 08, 2019 6:24 pm
by MrFariator
Just quick two cents, I think you are creating unnecessary garbage by wrapping the varargs into a table, only to unpack it a few lines later. This kind of code, unpack() in particular, can be rather costly if those callbacks are going to be called often.

Code: Select all

for _, v in ipairs(callbacks) do
    Container[v] = function(self, ...)
        for _, child in ipairs(self.children) do
            if type(child[v]) == "function" then
                child[v](...)
            end
        end
    end
end