From f2115eed1d22557691c21b9b65074585bc844567 Mon Sep 17 00:00:00 2001 From: mcc Date: Thu, 7 Feb 2019 13:34:00 -0500 Subject: [PATCH] Allow inheritance of _init from more than one level up Currently _init is exempted from "fat inheritance", and _init inheritance works by a strange workaround where the base class exactly one level up is checked for _init at constructor time. This appears to be done so that :super() can work properly, but it means that _init cannot be inherited from a grandparent. This patch adds a _parent_with_init field to all relevant classes which points to the most recent ancestor with an _init implementation. This simplifies both __call and _class and might actually be a performance improvement (it removes a loop). --- lua/pl/class.lua | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/lua/pl/class.lua b/lua/pl/class.lua index 847f442b..f6467660 100644 --- a/lua/pl/class.lua +++ b/lua/pl/class.lua @@ -17,22 +17,21 @@ local compat -- this trickery is necessary to prevent the inheritance of 'super' and -- the resulting recursive call problems. local function call_ctor (c,obj,...) - -- nice alias for the base class ctor - local base = rawget(c,'_base') - if base then - local parent_ctor = rawget(base,'_init') - while not parent_ctor do - base = rawget(base,'_base') - if not base then break end - parent_ctor = rawget(base,'_init') + local init = rawget(c,'_init') + local parent_with_init = rawget(c,'_parent_with_init') + + if parent_with_init then + if not init then -- inheriting an init + init = rawget(parent_with_init, '_init') + parent_with_init = rawget(parent_with_init, '_parent_with_init') end - if parent_ctor then + if parent_with_init then -- super() points to one above whereever _init came from rawset(obj,'super',function(obj,...) - call_ctor(base,obj,...) + call_ctor(parent_with_init,obj,...) end) end end - local res = c._init(obj,...) + local res = init(obj,...) rawset(obj,'super',nil) return res end @@ -146,6 +145,7 @@ local function _class(base,c_arg,c) c.__index = c setmetatable(c,mt) if not plain then + if base and rawget(base,'_init') then c._parent_with_init = base end -- For super and inherited init c._init = nil end @@ -160,15 +160,12 @@ local function _class(base,c_arg,c) if not obj then obj = {} end setmetatable(obj,c) - if rawget(c,'_init') then -- explicit constructor + if rawget(c,'_init') or rawget(c,'_parent_with_init') then -- constructor exists local res = call_ctor(c,obj,...) if res then -- _if_ a ctor returns a value, it becomes the object... obj = res setmetatable(obj,c) end - elseif base and rawget(base,'_init') then -- default constructor - -- make sure that any stuff from the base class is initialized! - call_ctor(base,obj,...) end if base and rawget(base,'_post_init') then