[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: metatables reprise
- From: "Wim Couwenberg" <w.couwenberg@...>
- Date: Tue, 14 Jan 2003 19:01:18 +0100
Hi,
> Regarding Wins reply to my previous query about metatables (not)
> having metatables, that was very informative, thanks. However, it did
> not really help with the problem at hand.
Yes, I admit your problem wasn't entirely clear to me from your last mail,
so I made a (semi-)educated guess... :-)
[... snip snip ... lots of stuff deleted ...]
> Back to the problem: What I would really like to have is a mechanism
> whereby a metatable can redirect calls to metamethods in a way that
> they actually appear as undefined when they are not defined in
> whatever place they are redirected to. Does anyone have an idea how I
> could achieve this?
All this sounds to me as if you more or less want to mimic the Python class
system. The code below comes a long way. Classes are created with the
"class" function. Classes can be subclassed using the "subclass" class
method. As in Python I use the function call on a class to create an
instance. If the class (or a superclass) provides an "__init" method this
will sere as a constructor.
Also take a look at the example using addition. I followed the Python rule
here to try a __radd ("reverse add") method on the argument if an instance
fails to provide an __add method itself. This is only an example, you can
implement it differently of course. (There are some nags with this "double
dispatching" of binary operators, but that is a different story altogether.)
Anyway, here's is some code:
-- a fairly simplistic Pythonesque class system setup...
local class_proto = {}
local class_meta = {}
local instance_meta = {}
function class_proto:subclass(table)
if getmetatable(self) ~= class_meta then
print "subclass expects a class."
return
end
table.__super = self
setmetatable(table, class_meta)
return table
end
function class_meta:__index(index)
local super = rawget(self, "__super")
if super then return super[index] end
return class_proto[index]
end
function class_meta:__call(...)
local ins = {__class = self}
setmetatable(ins, instance_meta)
local init = self.__init
if init then init(ins, unpack(arg)) end
return ins
end
function instance_meta:__index(index)
local class = rawget(self, "__class")
return class and class[index]
end
function instance_meta:__add(other)
local add = self.__add
if add then return add(self, other) end
add = other.__radd
if add then return add(other, self) end
print "__add not supported"
end
-- note: other arithmetic &c. is similar...
function class(table)
setmetatable(table, class_meta)
return table
end
-- let's give it a spin!
-- create a class hierarchy...
ca = class {
__init = function(self, x) self.x = x end,
}
cb = ca:subclass {
__add = function(self, other) return self.x + other.x end,
__radd = function(self, other) return self.x + other.x end,
}
-- create instances...
a = ca(3)
a2 = ca(7)
b = cb(5)
-- perform some arithmetic...
print(a + b)
print(b + a)
-- but this will fail...
print(a + a2)
Maybe this helps a bit more!
Bye,
Wim