Nicolas B.
Nicolas B.

Reputation: 1318

Use of metatables in Lua

I'm trying to implement a object notation in Lua scripts. Here is what I succeeded to do with the C API:

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

Answers (2)

Nicol Bolas
Nicol Bolas

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

daurnimator
daurnimator

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;

  • 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)

Upvotes: 4

Related Questions