return function(meta)
local class = {
id = function(instance)
return getmetatable(instance) == meta
end;
merge = function(dest, src)
for k,v in pairs(src) do
dest[k] = v
end
if meta.clone then meta.clone(dest) end
end;
}
class.clone = function(instance)
local new = {}
class.merge(new, instance)
setmetatable(new, meta)
return new
end
class.change = function(orig, delta)
local new = class.clone(orig)
class.merge(new, delta)
return new
end
class.mk = function(...)
local new
if #{...} == 1 then
if class.id((...)) then
-- default copy constructor
return class.clone((...))
elseif meta.cast then
if type((...)) == 'table' then
for from, conv in pairs(meta.cast) do
if from.id and from.id((...)) then
new = conv((...))
goto setup
end
end
else
local conv = meta.cast[type((...))]
if conv then
new = conv((...))
goto setup
else assert(false) end
end
end
end
new = meta.construct(...)
::setup::
setmetatable(new, meta)
return new
end
setmetatable(class, { __call = function(self, ...)
return self.mk(...)
end })
return class
end