Class extension

Hi. I’ve extended the class implementation provided by codea to support (even in a rough way) also interfaces implementation. I was looking for something similar to what AS3 allows to do, having no multiple inheritance but having single inheritance plus multiple interfaces implementation. The code is based on a ClassLib.lua I founded on

-- Class.lua
-- Compatible with Lua 5.1 (not 5.0).

class(ancestor, interfaces...)

- class(base) 
inherits from base, so is_a(base) is true

class(base, interface1,..,interfacen)
inheriths from base and implements all the interfaces, so
is_a is true only for base, while implements is true for all the interfaces, and also for base

class(nil, interface1,..,interfacen)

implements interfaces but without inheritance, so is_a is true only for self name and i plements is true for all the interfaces


pay attention to symbol redefinition. in init phase a warning is logged when a symbol is redefined but no more

local reserved =
    __index          = true,
    _base            = true,
    is_a               = true,
    implements   = true,
    init                 = true

function class(...)
    local c = {}    -- a new class instance

    local args = {...}
    if table.getn(args) then
        local base = args and args[1] or nil
        if type(base) == 'table' then
            -- our new class is a shallow copy of the base class!
            for i,v in pairs(base) do
                c[i] = v
            c._base = base
        for _,i in pairs(args) do
            if type(i) =='table' then
                for k,v in pairs(i) do
                    if not reserved[k] and type(i[k]) == 'function' then
                        if c[k] then
                            print("warning " .. k .. 
                                " is already defined")
                        c[k] = v

    -- the class will be the metatable for all its objects,
    -- and they will look up their methods in it.
    c.__index = c

    -- expose a constructor which can be called by <classname>( <args> )
    local mt = {}
    mt.__call = function(class_tbl, ...)
        local obj = {}
        if class_tbl.init then
            -- make sure that any stuff from the base class is 
            if base and base.init then
                base.init(obj, ...)

        return obj

    c.is_a = function(self, klass)
        local m = getmetatable(self)
        while m do 
            if m == klass then return true end
            m = m._base
        return false
    c.implements = function(self, interface)
            -- Check we have all the target's callables
        for k, v in pairs(interface) do
            if not reserved[k] and type(v) == 'function' and 
                type(self[k]) ~= 'function' then
                return false
        return true

    setmetatable(c, mt)
    return c

Single inheritance with multiple interfaces is quite good! It’s like Java. Have you tested this? Hope this would be accepted by TLL. More advance OO feature is nice. :slight_smile:

Think you, @shrike. Your approach has jogged my memory and made me do a big forehead slap. There’s a good use for a similiar implementation in my current project. Should actually simplify some of the copy, copy, copy hole I’ve dug myself.

You should check out MiddleClass, which @JockM mentioned in this thread:

It has support for mixins, a powerful way to add interfaces to classes.

@shrike Very nice! You might want to take a look at MiddleClass if you haven’t. There are some nice ideas in there you might want to borrow — such as mixins and the ability to address the superclass.

Hi @bee, yes I’ve tried it and It seems to work as I expected. Just adding that to a project let you override basic class() definition, without changing at all the original behaviour (consider that the most of the code IS the original source code). It just adds functionalities if any interfaces is declared and anyway without affecting the inehritance (at least until there’s no collision of names).

I would like to do some more little changes and improvement but for now I had just one specific need and it’s addressed, so I will do that later. Thanks @toadkick and @JockM, I’ll sure give a look at MiddleClass implementation, it seems very interesting!