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
Related
I'm writing a module to generate some kind of encrypted access tokens. The encryption library I'm going to use (lua-resty-string.aes) uses the following method of class and class instance initialization:
local _M = { _VERSION = '0.14' }
local mt = { __index = _M }
function _M.new(...)
...
return setmetatable({ ... }, mt)
end
What is the fundamental difference of this initialization method with the following one (I'm more familiar with)?
Class = {}
Class.__index = Class
function Class.new()
return setmetatable({}, Class)
end
When I need to check is the variable passed to my function is an instance of the required class, for the second case I can use the following:
if getmetatable(obj) == Class then ...
However this is not working for the first case of initialization. I found the following works correctly:
local aes = require("resty.aes")
if (getmetatable(obj) or {}).__index == aes then ...
But I'm not sure is it OK or is there something more convenient to do it right? And what are the benefits of using the first method of class instance initialization?
Metatable-based classes
First of all, _M is just a naming convention for a module "namespace". You could name it "module" or "Class" as in your second example.The only real difference is the separation of metatable and "methodtable" / "class" table:
local Class = {}
local metatable = { __index = Class }
function Class.new(...)
...
return setmetatable({ ... }, metatable)
end
cleanly separates the two; the metatable is a local variable and thus kept "private" to the class (if the __metatable field is set, it can further be hidden from getmetatable). If the metatable should be exposed for convenient checks, one way to go would be a metatable field in the Class table:
Class.metatable = metatable
the other pattern just mushes the metatable and methodtable in the same table. Lua's metamethod naming using a double underscore as prefix (e.g. __index) is designed to allow this:
local Class = {}
Class.__index = Class
function Class.new(...)
...
return setmetatable({ ... }, metatable)
end
it requires a circular reference in the Class table (Class.__index); the metatable can be accessed from anywhere as long as the Class table is available because it is the metatable. Downsides of this include (1) potentially worse performance (due to hash collisions, because your metatable contains both the methods and the metamethods) and (2) somewhat dirty: If I inspected your Class table, it won't be neatly separated in metamethods and class methods; I'd have to separate it myself based on method naming.
It also means that indexing instances or the Class table allows "seeing" the underlying implementation which should probably be abstracted away / only accessible through indexing / using the operators / calling: Class.__index and instance.__index will be Class.
Instance checking
Now to the problem of checking whether an object is an instance of a Class: If the second approach is used, comparing the return value of getmetatable works:
if getmetatable(obj) == Class then
-- object is an instance of the class
end
if the metatable is exposed as Class.metatable or the like (may remind you of Object.prototype in JS), this works very similarly:
if getmetatable(obj) == Class.metatable then
-- object is an instance of the class
end
alternatively, the Class may implement it's own isinstance method that checks against the "private" (local) metatable:
function Class.isinstance(table)
return getmetatable(table) == metatable
end
a third alternative to allow the simply comparison against Class would be to set the __metatable field to Class:
local metatable = {__index = Class, __metatable = Class}
that way, the metatable is neatly localized and separated from the Class, yet from the outside it seems as if the "mushy" pattern was used.
If the metatable is however not exposed and no isinstance method is available, you may have to resort to hacks such as the one you have shown to implement this:
if getmetatable(obj).__index == Class then
-- object is an instance of the class
end
this doees however rely on __index being used in a specific way - a hidden implementation detail - and should, if possible, not be used in practice. Suppose __index is changed to an actual metamethod to log a warning because a field has been deprecated:
function metatable.__index(self, field)
if field == "deprecated_field" then warn"deprecated_field is deprecated, use field instead!"
return Class[field]
end
and suddenly your check breaks because the assumption that metatable.__index == Class simply doesn't hold anymore. An alternative hack to consider would be obtaining a metatable from an instance:
local instance = Class(...)
local class_metatable = getmetatable(instance)
...
if getmetatable(obj) == class_metatable then
-- object is probably an instance of the class
end
I'm using tolua++ to automatically expose C++ types to Lua. It seems that when I expose some type, e.g.
struct TestComponent
{
float foo;
string bar;
}
What tolua does (at least this is what it seems like to me) is add a new metatable to the lua environment (in this case it would just be called TestComponent) with some regular metamethods such as __add, __lt, as well as __index, __newindex, etc. It also has some custom functions (called .set and .get) which seem to be used when you get or set certain members of the struct/class. The type of TestComponent here seems to be just "table".
However, what it seems to lack, for simple structure definitions like above, are functions/methods to create a new instance of the type TestComponent, e.g.
a = TestComponent:new()
The question, then, is, how do I create a new instance of this type and assign it to a variable? For example, to hand it to a function that expects an argument of type TestComponent.
It's been a few years since I used tolua++, but based on the docs it appears that if your struct had a constructor, then you could create the object with a = TestComponent() or a = TestComponent:new() (both should work, unless you have an older version of tolua++). Without a constructor in the C++ struct, the docs don't say, but based on what you state, it seems like the TestComponent becomes a regular table object with the given fields and associated values, in which case it does not make sense to have a constructor (the table is the object, you can't create multiple instances of it).
So if you can edit the C++ header of the struct to add a constructor to it, it'll probably work. If you can't do that, then you could define a constructor yourself (note: not tested):
function TestComponent:new()
local obj = {}
for k,v in pairs(self) do
obj[k] = v
setmetatable(obj, self)
return obj
end
You might have to filter the keys so you only get values (not functions, for example), or replace the loop with explicit assignments such as:
function TestComponent:new()
local obj = {}
obj.foo = self.foo
obj.bar = self.bar
setmetatable(obj, self)
return obj
end
I want to be able to have 'objects' with certain functions that refer to themselves (I have no idea what to call this) in Lua. I have seen code of what I'm trying to do but I have never understood what any of it actually means. I have tried looking over the Lua website but no luck.
Basic Code:
table = {}
function newTable(...)
...
return setmetatable(table)
end
function table:funcName(...)
...
end
Can someone explain what is going on here and how I can use this please? Thanks for reading!
missingno already mentioned one resource that explains how this works. You can also check out lua wiki's OOP section for more explanation and examples.
To summary briefly your example, starting with how to use it. Note, I changed some of the names so it doesn't affect the standard modules that comes with lua. You create a new object by calling newObject. You can invoke that object's methods using : followed by the method name:
-- create two instances
object1 = newObject()
object2 = newObject()
-- call 'my_function' method for object1
object1:my_function()
You'll need to know a bit about metatables to understand how this machinery works behind the scenes. When you perform a call like:
object1:my_function()
That is just syntax sugar for:
object1.my_function(object1)
This can be broken down further into:
object1["my_function"](object1)
Now object1 is just an empty table returned by newObject -- it doesn't have a "my_function" key. Normally this would result in an error because you're trying to call a nil value. However, you can change this behavior using metatables. The basic idea is to setup the __index metamethod to point to a table that holds your class methods:
object_table = {}
object_table.__index = object_table
function newObject(...)
return setmetatable({}, object_table)
end
The method lookup process will then look like this: object1 -> table. If object1 doesn't have a key, table is consulted next. If table has that key the associated value is returned. If table doesn't have it either then nil is returned since table doesn't have a metatable.
With this setup you can "override" a method for a particular object instance by just assigning the method name and function as key-value pair for that object.
object2.my_function = function (...)
-- do something different
end
I'm not too knowledgeable on objects in Lua so bear with me.
Sample Code:
Colors = {
primary = "BF2626",
primaryGradient = {"CC2929", "B32424"}
}
function Colors:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
function Colors:setPrimaryGradient()
self.primaryGradient[1] ="Changed"
end
function Colors:setPrimary()
self.primary ="00FF00"
end
a =Colors:new()
b =Colors:new()
b:setPrimaryGradient()
b:setPrimary()
print(a.primaryGradient[1])
print(b.primaryGradient[1])
print(a.primary)
print(b.primary)
Output:
Changed
Changed
BF2626
00FF00
What am I doing wrong?
Why does the variable primary keep its value for each object but the tables don't?
Thanks.
Your new function sets up a metatable for the empty table. This metatable has functions and internal data. It also sets up an __index metamethod. That's important.
Your setPrimaryGradient method takes self as an implicit parameter. In this case, self is the new table that was created in new. Your problem is here:
self.primaryGradient[1] is not a single construct. It is two separate operations. Let's write it out how Lua uses it: self["primaryGradient"][1]. See the problem?
The first part, self["primaryGradient"] will check the self table and get it's primaryGradient member. The problem is that because self has an __index metamethod, and there is no primaryGradient member in self directly, it will therefore use the __index metamethod directly. So it will get the primaryGradient from the metatable. A metatable that is shared.
The [1] part will then be executed on the metatable's member, and a value will be stored in the first element of the primaryGradient from the metatable.
The reason why setPrimary doesn't exhibit the same problem is quite simple. self.primary is one operation. Because it's a table access followed by an assignment operation, Lua will not use the __index metamethod. It will instead use the __newindex metamethod. Since you didn't define one for self's metatable, it will use the default logic: create a new member in self and set its value.
The reason setPrimaryGradient doesn't use __newindex is because it does. Just not for the access to self. It uses __newindex on the access to self["primaryGradient"]; only the last table access gets the __newindex call.
If you want to initialize your types with some default values that you can then modify, you need to copy those values. You can't just reference global ones sometimes. Well, you could, but it would be a big pain to set up.
The problem can be easily fixed in this way:
Colors = {
primary = "BF2626",
primaryGradient = {"CC2929", "B32424"}
}
Colors.primaryGradient.__index = Colors.primaryGradient
function Colors:new(o)
o = o or {primaryGradient = setmetatable({}, self.primaryGradient)}
setmetatable(o, self)
self.__index = self
return o
end
I'm trying to implement a object notation in Lua scripts.
Here is what I succeeded to do with the C API:
I created a new global table "Test" as a class and added a field "new" in it, pointing to a function written in C
i.e I can do this in lua code: "local obj = Test.new()" (it calls the function "new")
The "new" C function creates and returns a new table, and registers functions in it as fields (e.g "add", "count"...)
i.e I can do this: "obj:add("mike")" and "obj:count()" (obj is passed as first arguments with the ":" notation)
2 questions:
1) Everything works as expected, but the thing I'm wondering is: What is the advantage of using metatables in my case?
I see everywhere that metatables can help me to achieve what I tried to do, but I don't understand where they would be useful?
Adding fields to tables as methods isn't correct?
How could metatables help me (If added as my tables metatables)?
2) In fact I'm trying to reproduce the behaviour of C++ in Lua here.
For example, when I write this in C++: "Test *obj = new Test();"
I expect C++ and the constructor of Test to return me a pointer of an instance of Test.
This is exactly what I'm trying Lua to do for me.
The thing is that I use a table in this case, as the return of "new", but not a pointer so I can call methods on it later with Lua (using its fields), like a standard C++ object (with the operator ->).
To be able to retreive the actual pointer of my class in the C fonctions, I added a field "ptr" (light uservalue) to the table returned by "new". Without it, I would have been able to manipulate only the Lua table in my C function, nothing more (so no more method calls on the real pointer).
My second question is, Is it the right way to do it?
Do you have better idea on how to be able to manipulate my pointer everywhere without this "ptr" field?
Thank you,
Nicolas.
The main reason is that you get the __index metamethod.
Without it, every instance of a object has to have all the functions associated with it: which can make tables why large; and use a lot of memory.
local methods = {
foo = function() return "foo" end ;
bar = function() return "bar" end ;
bob = function() return "bob" end ;
hen = function() return "hen" end ;
}
So you have either
function new_no_mt ( )
local t = {}
for k , v in pairs ( methods ) do t [ k ] = v end
return t
end
vs
local mt = { __index = methods ; }
function new_mt ( )
return setmetatable ( { } , mt )
end
There are other benefits too;
defining operators;
easy type comparison via comparing metatables.
Changing method in metatable changes it for all objects, but changing it on one object only changes it for that object.
Otherwise, what you are trying to do sounds like the perfect situation for userdata.
userdata can only be indexed when you have an __index metatmethod (theres no table to put methods in)
What is the advantage of using metatables in my case?
Here's one.
Test.new = function() end
I just destroyed your ability to create new Test objects globally. If you had protected Test with a metatable, I would have had to really work to be able to do that.
Here's another:
local myTest = Test()
You can't do that without a metatable (overload the __call metamethod). And it looks much more natural for Lua syntax than calling Test.new.
And another:
local testAdd = Test() + Test()
Operator overloading. You can't do that without metatables.
Also:
This is exactly what I'm trying Lua to do for me.
Here's a tip: don't.
Different languages are different for a reason. You should do things in Lua the Lua way, not the C++ way. I can understand wanting to provide certain C++ mechanisms (like overloading and so forth), but you shouldn't use new just because that's what C++ uses.
Also, there are plenty of libraries that do this work for you. SWIG and Luabind are two big ones.