Skip to content

Instantly share code, notes, and snippets.

@sclark39
Last active August 29, 2015 14:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sclark39/8ddcd4a0ba3de3b922ea to your computer and use it in GitHub Desktop.
Save sclark39/8ddcd4a0ba3de3b922ea to your computer and use it in GitHub Desktop.
Lua class lib with 'base' helper method
-- test.lua
-- using the class lib and the introspective base helper method
class 'A'
function A:test()
print "Hi"
end
class 'B' (A)
function B:test()
base() -- self.base.test( self ) would actually cause a stack overflow when calling C:test()
print "Hello"
end
class 'C' (B)
C:test()
-- prints
-- Hi
-- Hello
-- test2.lua
-- much more performant alternative to get similar 'base' sugar
class 'B2' (A)
local base = B2.test -- 'B2' here so if subclass gets modified in line above, this doesn't need to be updated
function B2:test()
base( self )
print "Hello"
end
class 'C2' (B2)
C2:test()
-- prints
-- Hi
-- Hello
-- class.lua
local function isa( self, name )
repeat
if self.__name == name then
return true
end
self = self.__base
until not self
return false
end
function class ( name )
local class = {
__name = name;
isa = isa;
}
local instance_mt = { __index = class; }
class.new = function(...)
local instance = setmetatable( {}, instance_mt )
instance:init( ... )
return instance
end
getfenv( 2 )[ name ] = class
return
setmetatable( {}, {
__call = function(t,superclass)
class.__base = superclass
setmetatable( class, {__index = superclass } )
end
} )
end
local getinfo,getlocal,rawget = debug.getinfo, debug.getlocal, rawget -- make local for speed
function base( ... )
local methodname,caller,self
do -- inspect stack to find caller and self
local callerinfo = getinfo(2, "nf")
local localname, localval = getlocal(2, 1)
assert( callerinfo.namewhat == "method" and localname == "self" and localval )
methodname = callerinfo.name
caller = callerinfo.func
self = localval
end
local nextbase,basecall -- loop vals
nextbase = self
repeat -- find the function that called base
basecall = rawget( nextbase, methodname )
if basecall == caller then
break
end
nextbase = nextbase.__base
until not nextbase
nextbase = nextbase.__base
while nextbase do -- call the next one up the inheritence tree
basecall = rawget( nextbase, methodname )
if basecall ~= caller then
return basecall( self, ... )
end
nextbase = nextbase.__base
end
error( "base() called by non-overrided method" )
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment