lua-users home
lua-l archive

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


> 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

Isn't it "self"? Every method will get it when called with ":".

> * The current point in the inheritance hierarchy

In my class system, this is a _CLASS field found on every instance that
points to their respective classes, which in turn hold their methods and
have a _SUPER field.

> 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

Shouldn't you create the methods table, i.e. Base.methods = {}?

> 
>     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.   

Those would be "self" and "self._CLASS".

I see you store methods inside a field within the class table, I prefer
to hide that implementation characteristic from users. If we want to
have class systems which are interoperable I think we should agree on a
set of standards before moving on. This is what I would like to have:

1) Defining a new class

NewClass = class([SuperClass] {, SuperClass})

It's not strictly necessary to have it standardized, if you're writing a
Lua app that uses more than one class system, you can elect on of them
and use its syntax to create new classes, but it's good to have just one
way of doing it no matter which class system you're using.

2) Defining the constructor

function Class:new([argument], {, argument})

The name of the constructor, "new" in this case, should be standardized.
Constructor overloading would be accomplished by examining the number of
arguments and their types.

3) Defining a method

function NewClass:blit([argument] {, argument})

4) Creating an instance of a class

instance = Class([argment] {, argument})

Like item 1, we don't have to have it standardized, but again it's good
to have only one way to create instances.

The constructor "new" would be called with a new instance of the class
and all arguments passed to Class, to avoid having to create the
instance inside the constructor and initializing it's "hidden" fields
that make the class system work.

5) Calling methods

instance:method([argument] {, argument})

Methods should always be called with ":", having mixed ways of calling
methods isn't a good thing.

6) Calling inherited methods

instance:super.method([argument] {, argument})

I don't see why calling inherited methods from super classes other than
the direct super class is needed.

7) Accessing properties

instance.property

I think that those standards plus the class system package proposed by
Steve Donovan and augmented by me would allow completely, interoperable
class systems, and no one would be forced to use just one class system
throughout the entire application. But I may be wrong :)

Regards,

Andre de Leiradella