mirror of
https://github.com/1bardesign/batteries.git
synced 2024-11-26 15:44:35 +00:00
[fixed] super call in case where subclass called from doesn't have implementation - hurts runtime performance but the previous impl was a potential infinite loop!
This commit is contained in:
parent
9d0a7d6e86
commit
fff1474c37
47
class.lua
47
class.lua
@ -7,22 +7,24 @@
|
|||||||
|
|
||||||
local function class(inherits)
|
local function class(inherits)
|
||||||
local c = {}
|
local c = {}
|
||||||
c.__mt = {
|
--class metatable
|
||||||
__index = c,
|
|
||||||
}
|
|
||||||
setmetatable(c, {
|
setmetatable(c, {
|
||||||
--wire up call as ctor
|
--wire up call as ctor
|
||||||
__call = function(self, ...)
|
__call = function(self, ...)
|
||||||
return self:new(...)
|
return self:new(...)
|
||||||
end,
|
end,
|
||||||
--handle single inheritence
|
--handle single inheritence chain
|
||||||
__index = inherits,
|
__index = inherits,
|
||||||
})
|
})
|
||||||
|
--instance metatable
|
||||||
|
c.__mt = {
|
||||||
|
__index = c,
|
||||||
|
}
|
||||||
--common class functions
|
--common class functions
|
||||||
|
|
||||||
--internal initialisation
|
--internal initialisation
|
||||||
--sets up an initialised object with a default value table
|
--sets up an initialised object with a default value table
|
||||||
--performing a super construction if necessary and assigning the right metatable
|
--performing a super construction if necessary, and (re-)assigning the right metatable
|
||||||
function c:init(t, ...)
|
function c:init(t, ...)
|
||||||
if inherits and inherits.new then
|
if inherits and inherits.new then
|
||||||
--construct superclass instance, then overlay args table
|
--construct superclass instance, then overlay args table
|
||||||
@ -45,17 +47,38 @@ local function class(inherits)
|
|||||||
--get the inherited class for super calls if/as needed
|
--get the inherited class for super calls if/as needed
|
||||||
--allows overrides that still refer to superclass behaviour
|
--allows overrides that still refer to superclass behaviour
|
||||||
function c:super()
|
function c:super()
|
||||||
return inherits or c
|
return inherits
|
||||||
end
|
end
|
||||||
|
|
||||||
--delegate a call to the super class, by name
|
--delegate a call to the superclass, by name
|
||||||
--still a bit clumsy but cleaner than the inline equivalent
|
--still a bit clumsy but much cleaner than the inline equivalent,
|
||||||
|
--plus handles heirarchical complications, and detects various mistakes
|
||||||
function c:super_call(func_name, ...)
|
function c:super_call(func_name, ...)
|
||||||
local f = self:super()[func_name]
|
--
|
||||||
if f then
|
assert(type(func_name) == "string", "super_call requires a string function name to look up")
|
||||||
return f(self, ...)
|
--todo: memoize the below :)
|
||||||
|
local first_impl = c
|
||||||
|
--find the first superclass that actually has the method
|
||||||
|
while first_impl and not rawget(first_impl, func_name) do
|
||||||
|
first_impl = first_impl:super()
|
||||||
end
|
end
|
||||||
error("failed super call - missing function "..tostring(func_name).." in superclass")
|
if not first_impl then
|
||||||
|
error("failed super call - no superclass in the chain has an implementation of "..func_name)
|
||||||
|
end
|
||||||
|
--get the superclass of that
|
||||||
|
local super = first_impl:super()
|
||||||
|
if not super then
|
||||||
|
error("failed super call - no superclass to call from")
|
||||||
|
end
|
||||||
|
|
||||||
|
local f = super[func_name]
|
||||||
|
if not f then
|
||||||
|
error("failed super call - missing function "..func_name.." in superclass")
|
||||||
|
end
|
||||||
|
if f == self[func_name] then
|
||||||
|
error("failed super call - function "..func_name.." is same in superclass as in derived; this will be a infinite recursion!")
|
||||||
|
end
|
||||||
|
return f(self, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
--done
|
--done
|
||||||
|
Loading…
Reference in New Issue
Block a user