Search code examples
functionobjectlualua-table

How to save a function of an Object/table to a variable to be called from this variable in Lua?


I'm experimenting with Lua OOP (Object Oriented Programming) but I'm experiencing some issues.

Here is a sample code with comments:

Object = {string = "Default"}

function Object:new()
    local o = {}
    setmetatable(o, {__index = self})
    -- o.string = "Default"
    return o
end

function Object:SayHi(input)
    if input == nil then
        input = ""
    else
        local temp = input
        input = " " .. temp
    end
    print("Hi!" .. input)
end

function Object:CallHiFunct()
    local temp = "Called from CallHiFunct"
    self:SayHi(temp)
end

function Object:PrintString()
    print(self.string) -- Variable named string from Object
end

object1 = Object:new() -- Returns new metatable to object1
object1:SayHi() -- Prints Hi!
object1:CallHiFunct() -- Prints Hi! Called from CallHiFunct
object1:PrintString() -- Prints Default

print()
print()

funct_object1 = object1.SayHi
funct_object1() -- Prints Hi!

funct2_object1 = object1.PrintString
funct2_object1() -- Error: attempt to index a nil value (local 'self')

funct2_object1 = object1:PrintString() -- if object1:PrintString Error: function arguments expected near 'funct2_object1'
funct2_object1() -- Error: attempt to call a nil value (global 'funct2_object1')

I'm trying to save a function from an object/table but I'm having problems with self being nil.

How can I properly do this to keep the function with the object?

.

The reason why I'm doing this is because I'm using a function specified in a library which accepts function as an argument.

I think something like this:

function Example(funct)
    funct() -- calls it here
end

To be exact the function is actually: GUI:AddButton(arguments...):AddEventHandler(event, funct)

(event: when it is activated, funct: to call when activated)

but I'm not exactly sure what is inside.

Anyway. Ignoring this library is it possible to save a function from an "object" to variable to be called from this variable?

(I was unable to find any answer. I it already has been asked then link the question with the answers please.)

Thanks.


Solution

  • table:function(arguments) is purely syntactic sugar for table.function(table, arguments).

    (In the body of the function definition table is the implicit self, when defined with colon syntax.)

    As you have seen, this assignment

    funct2_object1 = object1.PrintString
    

    does not carry any information about object1 with it, and so this function call

    funct2_object1()
    

    errors out, looking for an explicit first argument to fill the role of self.

    If you had called funct2_object1(object1) the function would behave as expected.


    Given this callback-style function

    function Example(funct)
        funct() -- calls it here
    end
    

    it sounds like what you want is to create a closure around your OOP-style call, which you can do by enclosing it with a function (anonymous or otherwise).

    For example:

    local Object = {}
    
    function Object:new(data)
        return setmetatable({ data = data }, { __index = self })
    end
    
    function Object:do_something()
        print('Hello from', self, self.data)
    end
    
    local thing = Object:new(42)
    
    ----
    
    local function Example(funct)
        funct()
    end
    
    Example(function ()
        thing:do_something()
    end)
    
    Hello from  table: 0x55c65be628c0   42