Hello everyone!
I have come to write the following code quite often (it is just an example), but i am not happy of it:
Button = class(IconBox)
Button.updateStateIcon = IconBox.updateState
function Button:updateState(data)
self:updateStateIcon(data)
local data = data or {}
if data.infoVisible ~= nil then self:displayInfo( data.infoVisible ) end
end
Let me explain: i have many classes, build on top of each other.
I add new functionnalities to the new class, and i want to reuse the available ones.
However, for clarity and modularity, i want to use the same names for functions in all the classes.
In this example, the function is updateState.
So i want to reuse the updateState from IconBox in its derived class Button, add functionnalities, and still use the same name.
The only way i found to do it is this ugly Button.updateStateIcon = IconBox.updateState line.
So here is my question: Is there any more elegant way do achieve this?
The problem is that Button already knows it is a class drived from IconBox, so i dont want to write that down again. It would be very clean if i accepted to change the function name, but i want to keep the same one…
Hmm… Codea classes copy everything from the superclass to the new class, but it doesn’t support :, only .
Maybe you could, like IconBox.updateState, have a static function that would be copied?
IconBox = class()
IconBox.updateState = 0
IconBox.setUpdateState = function(state)
IconBox.updateState = state
end
-- Then all the normal code...
function IconBox:init()
-- ...
end
Button = class(IconBox)
Button.updateStateIcon = IconBox.updateState
function Button:updateStateIcon(data)
Button.setUpdateState(data)
local data = data or {}
--if data.infoVisible ~= nil then self:displayInfo( data.infoVisible ) end
end
Tested
Ugh… It’s like static voids and ints etc. in Java all over again…
@Jmv38 Ah, there are supers in Java, didn’t know about them in Codea. And if you look at my code, you’ll see it calls Button.setUpdateState(), which is never defined from within Button, but inherited from IconBox, because it uses . instead of :
Unfortunately my formulation above works with the 1rst level of derived class, but when i use it in a 2nd level, class derived from a class derived from a class, i get a stackoverflow error. @Toadkick any suggestion? I am sure you’ve already considered and solved this question?
super = setmetatable({},{
__index = function(tbl,k)
local _,v = debug.getlocal(2,1)
return v._base[k]
end
})
function setup()
A = class()
function A:fn()
print("A.fn called")
end
B = class(A)
function B:fn()
print("call super.fn")
super:fn()
end
b = B()
b:fn()
end
Thanks a lot @toffer.
Unfortunately your solution is also a stck overflow at level2:
-- test super
super = setmetatable({},{
__index = function(tbl,k)
local _,v = debug.getlocal(2,1)
return v._base[k]
end
})
A = class()
function A:fn()
print("A.fn called")
end
B = class(A)
function B:fn()
print("call super.fn")
super:fn()
end
C = class(B)
function C:fn()
print("call super.fn")
super:fn()
end
function setup()
b = B()
b:fn()
c=C()
c:fn()
end
@Jmv38 - nvm, I’m totaly wrong with that, the scope is not passed correctly.
this one should be better:
-- test super
super = setmetatable({},{
__index = function(tbl,k)
local fn = debug.getinfo(2).func
local _,scope = debug.getlocal(2,1)
local base = scope
repeat
base = base._base
until base[k] ~= fn
return function (...)
base[k](scope,unpack({select(2,...)}))
end
end
})
A = class()
function A:fn()
print("A.fn called ",self)
end
B = class(A)
function B:fn()
print("B.fn called ",self)
super:fn()
end
C = class(B)
function C:fn()
print("C.fn called ",self)
super:fn()
end
function setup()
b = B()
print("b", b)
b:fn()
c=C()
print("c", c)
c:fn()
end
[EDIT] Wow! Thanks a lot! I seemed to work, and i decided to measure the performance because debug is not supposed to be fast. So i did the following changes, where the print() statements where the slowest. So i commentedt out the print() and asked for a return value. And then i saw the returned values are nil. So it still doesnt work, sorry… Any idea?
-- test super
super = setmetatable({},{
__index = function(tbl,k)
local _,scope = debug.getlocal(2,1)
local ctx,base = debug.getinfo(2,"nf"),c
local name,fn = ctx.name,ctx.func
local base = scope
while base[name] ~= fn do
base = base._base
end
base = base._base
return function (...)
base[k](scope,unpack({select(2,...)}))
end
end
})
A = class()
function A:fn()
-- print("A.fn called ",self)
return "A.fn called "
end
B = class(A)
function B:fn()
-- print("B.fn called ",self)
return super:fn()
end
C = class(B)
function C:fn()
-- print("C.fn called ",self)
return super:fn()
end
function setup()
local a = A()
print("a", a)
local str = a:fn()
print(str)
print("----------")
local b = B()
print("b", b)
local t0 = os.clock()
local str = b:fn()
local t1 = os.clock()
print(str)
print(t1-t0)
print("----------")
local c=C()
print("c", c)
t0 = os.clock()
str = c:fn()
t1 = os.clock()
print(str)
print(t1-t0)
end