Engine
Engine

Reputation: 5420

Classes in Lua, how does it work

I'm new to Lua, and I'm trying to understand its OO part, for example :

lkw = {}
lkw.la= 0

function lkw:func(ge)
    self.la = self.la + ge
end

function lkw:new()
    local res = {}
    setmetatable(res, self)
    self.__index = self
    return res
end

mylkw = lkw:new()

in this example the "class" lkw can create object using new, but what do self and index mean ? should consider self as this in java/C++ and what is the index ?

Upvotes: 3

Views: 2686

Answers (1)

catwell
catwell

Reputation: 7048

This style of OOP is frequent in Lua. I do not like it because it is not explicit enough for me, but let me try to explain.

There are two confusing things: the use of the : sugar in function definitions and the use of the "class" as the metatable for its instances.

First, function a:b(...) is the same as a.b = function(self, ...), so let us remove all sugar:

lkw = {}
lkw.la = 0

lkw.func = function(self, ge)
    self.la = self.la + ge
end

lkw.new = function(self)
    local res = {}
    setmetatable(res, self)
    self.__index = self
    return res
end

mylkw = lkw.new(lkw)

Now, this is "prototypal inheritance". lkw is the "prototype" for instances like mylkw. This is similar but slightly different from a "class".

When the new constructor is called, lkw is passed as the self argument.

The second and third lines of the constructor are weird. This is probably easier to understand:

lkw.new = function(self)
    local res = {}
    setmetatable(res, {__index = lkw})
    return res
end

i.e.: if we do not find something in the instance we go look for it inside the prototype.

This explains how func works. The first time it is called, the instance will not contain a la key so lkw.la will be used.

The reason the code is not written this way is that the weird construction allows "prototypal inheritance": you could call "new" on mylkw and get an "instance of the instance" (i.e. in prototypal inheritance an instance and a child class are the same thing).

I think this is a very confusing feature. For reference this is about how I would write code that does about the same thing, with no inheritance:

local methods = {
    func = function(self, ge)
        self.la = self.la + ge
    end
}

local lkw = {
    new = function()
        return setmetatable({la = 0}, {__index = methods})
    end
}

local mylkw = lkw.new()

Upvotes: 5

Related Questions