Reputation: 1318
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.
Upvotes: 2
Views: 3552
Reputation: 473212
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.
Upvotes: 4
Reputation: 4311
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;
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)
Upvotes: 4