Created
November 11, 2010 10:51
-
-
Save aurora/672338 to your computer and use it in GitHub Desktop.
class implementation for lua
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function clone(object) | |
local dict = {} | |
local function clone(object) | |
if (type(object) ~= "table") then | |
return object | |
elseif (dict[object]) then | |
return dict[object] | |
end | |
dict[object] = {} | |
for k, v in pairs(object) do | |
dict[object][k] = clone(v) | |
end | |
return setmetatable(dict[object], clone(getmetatable(object))) | |
end | |
return clone(object) | |
end | |
local meta_methods = { | |
__add = true, __sub = true, __mul = true, __div = true, __mod = true, __pow = true, __unm = true, | |
__concat = true, __len = true, | |
__eq = true, __lt = true, __le = true, | |
__index = false, __newindex = false, __call = false, __gc = false | |
} | |
function class(parent) | |
local class = {__meta__ = {}} | |
if (type(parent) == 'table') then | |
-- clone parent class | |
class = clone(parent) | |
else | |
parent = nil | |
-- initialize base class | |
function class:__construct(...) | |
end | |
function class:__destruct(...) | |
end | |
function class:__clone(...) | |
end | |
end | |
class.__meta__.__index = class | |
class.__meta__.__gc = function(...) | |
self:__destruct(...) | |
end | |
setmetatable(class, { | |
__call = function(self, ...) | |
local instance = {} | |
setmetatable(instance, class.__meta__) | |
instance:__construct(...) | |
return instance | |
end, | |
__newindex = function(t, k, v) | |
if (meta_methods[k] == nil or type(v) ~= 'function') then | |
rawset(class, k, v) | |
elseif (meta_methods[k]) then | |
class.__meta__[k] = v | |
else | |
error("unable to set property") | |
end | |
end | |
}) | |
-- add additional methods, that should be available for each class | |
-- clone instance | |
function class:clone(...) | |
local class = clone(self) | |
class:__clone(...) | |
return class | |
end | |
-- check instance of some other class | |
function class:instanceof(class2) | |
if (class == class2) then | |
return true | |
elseif (type(parent) == 'table') then | |
return parent:instanceof(class2) | |
else | |
return false | |
end | |
end | |
-- layer for accessing parent methods in local scope | |
function class:parent() | |
return setmetatable({}, { | |
__newindex = function(...) | |
error('unable to modify parent') | |
end, | |
__index = function(_, k) | |
local v = rawget(parent, k) | |
if (type(v) == 'function') then | |
-- make sure, that parent class is called in child's scope | |
return function(_, ...) | |
v(self, ...) | |
end | |
elseif (v) then | |
-- return parent property value | |
return parent[k] | |
else | |
-- unable to resolve parent | |
return nil | |
end | |
end | |
}); | |
end | |
return class | |
end | |
-- a | |
a = class() | |
a.value = 'a' | |
function a:print() | |
print('class a : ', self.value) | |
end | |
function a:setWorld() | |
self.value = self.value .. " world!" | |
end | |
-- b | |
b = class(a) | |
b.value = 'b' | |
function b:print() | |
print('class b : ', self.value) | |
end | |
function b:setHallo() | |
self.value = 'hallo!' | |
self:setWorld() | |
end | |
-- c | |
c = class(b) | |
c.value = 'c' | |
function c:print() | |
print('class c : ', self.value) | |
self:parent():print() | |
self:setHallo() | |
print('class c : ', self.value) | |
print(self:parent().value) | |
end | |
-- test | |
test_a = a() | |
test_a:print() | |
test_b = b() | |
test_b:print() | |
test_c = c() | |
test_c:print() | |
-- instanceof | |
print(a:instanceof(a), a:instanceof(b), a:instanceof(c)) | |
print(b:instanceof(a), b:instanceof(b), b:instanceof(c)) | |
print(c:instanceof(a), c:instanceof(b), c:instanceof(c)) | |
-- number | |
number = class() | |
number.value = 0 | |
function number:__construct(value) | |
self.value = value | |
end | |
function number:__clone(value) | |
self.value = value | |
end | |
-- cast object of instance 'number' to a lua type number | |
function number:cast(v) | |
if (type(v) == 'table' and v:instanceof(number)) then | |
v = v.value | |
elseif (type(op1) ~= 'number') then | |
v = 0 | |
end | |
return v | |
end | |
function number:__add(op) | |
op = self:cast(op) | |
return self:clone(self.value + op) | |
end | |
---- | |
n1 = number(10) | |
n2 = number(20) | |
print(n1.value, ' + ', n2.value, ' = ', (n1 + n2).value) | |
-- money | |
money = class(number) | |
money.currency = 'EUR' | |
function money:__construct(value, currency) | |
self:parent():__construct(value) | |
self.currency = currency or self.currency | |
end | |
function money:cast(v) | |
if (type(v) == 'table' and v:instanceof(money)) then | |
if (self.currency ~= v.currency) then | |
error('unable to calculate with operands of different currency!\n') | |
end | |
v = v.value | |
else | |
v = self:parent():cast(v) | |
end | |
return v | |
end | |
---- | |
m1 = money(10) | |
m2 = money(20) | |
m3 = money(30, 'USD') | |
sum = m1 + m2 | |
print(m1.value, ' + ', m2.value, ' = ', sum.value) | |
print(sum.value, ' + ', m3.value, ' = ', (sum + m3).value) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The parent function fail on multiple inheritence:
Any ideas on how to fix this?