I am trying to understand what this function does. Can anyone explain this to me?
function newInstance (class)
local o = {}
setmetatable (o, class)
class.__index = class
return o
end
It is called like this:
self = newInstance (self)
This function apparently serves to provide a variant of OOP in Lua (a bit sloppy in my opinion).
This is a factory for a class.
It may be rewritten as follows, for clarity:
C = { }
C.foo = function(self) -- just some method, so class would not be empty
print("foo method called", tostring(self))
end
C.__index = C -- (A)
function newInstance(class)
return setmetatable({ }, class) -- (B)
end
Now if we create two new instances of C, we clearly see that both have a method foo(), but different self:
o1 = newInstance(C)
o1:foo() --> foo method called table: 0x7fb3ea408ce0
o2 = newInstance(C)
o2:foo() --> foo method called table: 0x7fb3ea4072f0
The foo methods are the same:
print(o1.foo, o2.foo, o1.foo == o2.foo and "equal" or "different")
--> function: 0x7fb3ea410760 function: 0x7fb3ea410760 equal
This is because table C (the "class") is an __index
((A)
above) of metatable of o1
and o2
, set in (B)
. But o1
and o2
are actually two different tables, created at (B)
(the "class instances" or "objects").
Note: we set C.__index
to be equal to C
itself at (A)
so we would reuse one table. Following has the same effect:
prototype = { }
prototype.foo = function(self) -- just some method, so class would not be empty
print("foo method called", tostring(self))
end
C = { __index = prototype }
function newInstance(class)
return setmetatable({ }, class)
end
o = newInstance(C)
This is used to achieve object-oriented behavior in Lua. Lua uses prototype-based inheritance (similar to Javascript) instead of class-based inheritance (like Java or C++). The idea is that all class methods are implemented as part of a prototype object and inheriting objects delegate to the prototype upon call.
For example, assume you want a class myClass
providing a method getMagicNumber
:
local myClass = {
getMagicNumber = function(self)
return self.theNumber;
end };
local obj = newInstance(myClass);
obj.theNumber = 42;
print(obj:getMagicNumber()); -- supposed to return 42
It's kind of a trivial example, but I hope you get the idea. What happens is this: newInstance creates a new table with its metatable pointing to myClass
and also ensuring that the __index
field of the metatable points to myClass as well.
As the Lua manual on __index
describes, when you now attempt to call getMagicNumber on that new table, the following happens: First Lua attempts to find the field getMagicNumber
in the obj
table. Since that table is empty though, it now searches its __index
table (myClass
) for that field. Since the field is found there, it now calls the function found in myClass
.
Programming in Lua discusses this mechanism in great detail if you need to know more.
You're not alone it took me a fair bit of time to grok this code. Here's my interpretation
each table can have a netatable, the metatable can store amongst other things functions indexed by name, and setmetatable sets the value of the metatable naturally enough.
The line class._index = .. is where the magic happens.
When you try to call a function using self.fn1(), Then lua looks up in the self a name fn1. If it can't find it then it looks in self's metatable for a table __index
, and looks for a 'fn1' in the table stored there.
Now the metatable for self in your example is class, so lua looks for an __index entry in the metatable (class) to see if there's a function named fn1 in that table, and there is, so it's returned. You need to set the __index for class back to itself so that lua will look in the same metatable - confusing hey.
(as an aside the assignment to __index only needs to happen once, but for some reason it's always done in the new operator in all the lua examples - I take it outside of the new in my classes - saves a few cycles)
You then return the new table o, lua is garbage collected so returning a local creates a new table each time.
function newInstance (class)
local o = {}
setmetatable (o, class)
class.__index = class
return o
end
hth
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With