lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Duck wrote:
...
If I want to tell a table t to be an instance of a class c, it seems that there are many choices. What are the pros and cons of each of these, for example:

 t.__index = c; setmetatable(t,t)

or:

 setmetatable(t,{__index=c})

or, after making c the target of its own metatable's __index in either of the above two ways, this:

 setmetatable(t,c)

This is a question I have pondered too.

I avoid the first approach except in special hacks (e.g. singletons). The first approach is making each instance be its own metatable. This implies that each instance contains references to all its metamethods (e.g. __add) even if, as is typically the case, all instances of the class share the same metamethods. It seems more storage efficient and logical to place the metamethods instead in the class as in the third approach.

Furthermore, the first approach prevents the simple idiom getmetatable(a) == getmetatable(b) to test whether objects a and b are of the same class. We might try a.__index == b.__index, but that presupposes that we can safely access the field "__index" of each object (e.g. an object is allowed to raise an error when indexed).

That leads us to the third approach, which I often use for traditional class-based OO.

The second approach makes the distinction between an object's metatable and the table holding the members common to the class. I don't see much benefit in that for OO, and, like the first approach, it doesn't share metamethod references across instances. It does, however, prevent accessing the metamethods when indexing the object. For example, in the third approach, o['__add'] == getmetatable(o).__add. There may be some atypical cases where you want to be able to store arbitrary keys in an object and have them not conflict with the names of metamethods.