lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


on 1/19/05 7:52 PM, André de Leiradella at leiradella@bigfoot.com wrote:

>> on 1/19/05 9:02 AM, PA at petite.abeille@gmail.com wrote:
>> 
>>>> . The syntax to call inherited methods
>>> 
>>> What about something like: anInstance:super:doIt()?
>> 
>> That would only work for one level of inheritance.
> 
> That depends on what super does inside its metamethods. It can search
> for the method inside itself and, if not found, search recursively in
> it's ancestors.

The issue I was raising was if A subclasses B subclasses C and each provides
an implementation of doIt, then you aren't passing enough information to
super for it to do it what it needs. One essentially needs two pointers:

* The instance object
* The current point in the inheritance hierarchy

> 
>> Maybe the C++ approach of explicitly naming the parent class has some
>> merit, though it also has maintenance issues. Those issues could be
>> handle by defining a local variable named something like "super" at
>> the beginning of a class declaration.
> 
> Not sure I'm following you here. This local variable "super" defined at
> the beginning of a class solves the problem you described for C++,
> right?

The super variable had to do with Lua though you can achieve some of the
same effects in C++ with a macro or a typedef.

Let's do a Lua version with Base and Derived and some simple syntax along
the lines of what's been proposed so far (though I make a distinction
between instance methods and class methods).

    Base = class()  -- no other base class

    function Base.methods:doIt()
        -- do something
    end

    Derived = class( Base )

    function Derived.methods:doIt()
        -- call the base method: How?
        -- do some more work
    end

How do we call the base method from the derived method? One approach is:

    function Derived.methods:doIt()
        Base.methods.doIt( self )
        -- do some more work
    end

This is the C++ approach. It's chief downfall comes if you change the
inheritance hierarchy and forget to update the places that call through. You
can mitigate that with a local variable:

    Base = class()  -- no other base class

    function Base.methods:doIt()
        -- do something
    end

    Derived = class( Base )

    local super = Base

    function Derived.methods:doIt()
        super.methods.doIt( self )
        -- do some more work
    end

You could actually cache the methods table in a local rather than the class
in this example.

If classes know their superclasses, we could also write:

    function Derived.methods:doIt()
        Derived.superclass.methods.doIt( self )
        -- do some more work
    end

With a certain amount of trickery and conventions, one might be able to
implement something like:

    function Derived.methods:doIt()
        self:super( Derived ):doIt()
        -- do some more work
    end

This, however, requires that super construct a proxy object which will have
special versions of the methods that will get the base instance and pass
that to the actual methods.

Finally, note that these sort of issues also exist in prototype-based and
delegation-based systems. We want to know both the object-of-entry into the
method chain together with our current point in that chain.

Mark