lua-users home
lua-l archive

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


lua-bounces@bazar2.conectiva.com.br wrote:
> Although there's more than one way to skin the OOP
> cat in Lua, it would be useful to have some conventions.
> 
> For example, consider a class browser.  Such code can't
> even assume that the methods are stashed in the
> object's metatable!  One solution is to expect class
> systems to export some standard functions:
> 
> 1)  _classes_defined
> A user-defined iterator for finding all the classes defined
> in the system.  (If it isn't defined, we can probably cope
> by browsing the global environment recursively)
> 
> 2) _base
> Any table intended to be used as a class will export
> a method _base, which may of course return nil.
> 
> 3) _methods
> Any class must define this iterator, which gives the
> available methods; from there, the debug interface
> could give us where they're physically defined.
> (Whether this gives _all_ inherited methods, or just methods defined
> by this class, is an interesting question. I'd say this should be an
> option)  
> 
> So no matter how one sets up one's object system,
> such a convention would allow general tools
> to be built that don't require detailed knowledge
> of the object system.
> 
> steve d.

I like your idea. Class systems could be packages that follow some
conventions to allow getting information of a particular system and to
make interoperability possible (e.g. using one class system to subclass
a class of another class system).

A class system package could return a table with some defined functions:

----------------8<----------------
local function _classes_defined()
	-- returns an iterator that will return
	-- each class defined in this system
end

local function _super_of(class)
	-- returns an iterator that will return
	-- each super class of the defined class
	-- (makes multiple inheritance possible)
end

local function _methods_of(class, inherited)
	-- returns an iterator that will return
	-- each method of the class, climbing up
	-- the inheritance tree of the class if
	-- the parameter inherited is true
end

local package = {
	classes_defined = _classes_defined,
	super_of = _super_of,
	methods_of = _methods_of
}

return package
----------------8<----------------

To make interoperability possible, some other functions have to be
defined:

----------------8<----------------
local function _inherited_method(class, method)
	-- returns a function that is the given
	-- method of some super class of class
	-- or nil if no such method exists
end

local function _new(class, constructor, ...)
	-- returns a new instance of class calling
	-- the provided constructor with the
	-- ... arguments or nil if the class
	-- wasn't defined in this system
end

local package = {
	classes_defined  = _classes_defined,
	super_of         = _super_of,
	methods_of       = _methods_of,
	inherited_method = _inherited_method,
	new              = _new
}

return package
----------------8<----------------

Also to make interoperability possible, each class must have a "private"
_PACKAGE field which points to the package table of the class system
where the class was defined, and each instance must have a "private"
_CLASS field which points to the class it's an instance of.

Helper functions can be written to make life easier when using
simultaneous class systems:

----------------8<----------------
function new(class, constructor, ...)
	return class._PACKAGE.new(class, constructor, ...)

function inherited(self, method, ...)
	local func = self._CLASS._PACKAGE.inherited_method(self._CLASS,
method)
	return func(self, ...)
end

-- in my class system I call "class" to
-- define a new class, passing it's super
-- classes as arguments
MirroredSurface = class(Surface)

-- override a constructor
function MirroredSurface:load(fileName)
	-- call the inherited constructor
	inherited(self, "load", fileName)
	-- call a function from a package that
	-- will mirror the image, surface is
	-- an userdata created by the inherited
	-- constructor
	SDL_gfx.mirror(self.surface)
end

Screen = new(Screen, 'init', 640, 480)
background = new(Surface, 'load', 'background.png')
joeLeft = new(Surface, 'load', 'joe.png')
joeRight = new(MirroredSurface, 'load', 'joe.png')

background:blit(screen, 0, 0)
joeLeft:blit(screen, 100, 100)
Screen:flip()
----------------8<----------------

Assumptions
-----------

. Multiple constructors can be defined

As Lua won't support method overloading, I think we should have multiple
constructors.

. Multiple inheritance can be used

Having super_of returning an iterator gives the programmer the choice of
having multiple inheritance or not, I do have in my class system to
mimic Java's interfaces.

. Methods must be called with ':'

Class system implementors must at least agree with this, it'll be
terrible for the programmer to have to remember to use ':' with some
instances and '.' with anothers.

. Properties must be accessed with '.'

Is there another way of doing it? Seriously, maybe all objects should be
opaque, and getter/setter methods provided. But this will increase
typing.

What I like
-----------

. Having classes from various class systems working toghether

What I don't like
-----------------

. The syntax to call constructors

Maybe lhf's token filter can help with that.

. The syntax to call inherited methods

Likewise.

. The repeated typing of 'self'

This has already been discussed, and today I found myself happily typing
'this.foo', 'this.bar' on class constructors of a Java application I'm
working on because I like constructor parameters to match the member
variables. I don't use 'this' in other methods too much though. I just
like I could have the option to use it or not... (no replies necessary).

. This whole class system interoperability thing

This whole thing could be avoided if Lua had it in the core, but I can't
ask for that after asking for the package system to be *out* of the core
:)

Conclusion
----------

It seems to me that class systems interoperability is possible, and I
think the community should agree on some standard (like the one proposed
here) before that package system comes and a lot of packages are made
with incompatible class systems.

Please don't try to check my code, that's quite a long time I don't code
in Lua (finishing my master degree's thesis). Please also forgive me if
I forgot something important, or if the proposal is totally useless...

Regards,

Andre de Leiradella