In my job, I have to use Lua to program some of our software. For
anything complex, I love OOP concepts. For those that don't know, Lua
doesn't have OOP, though it has some syntactic sugar to make basic OOP
possible.

So, I wrote a little OOP library based on Ruby's object model. I have
an Object 'class', and a Class 'class', and Class is an instance of an
Object, and instances of Class are themselves objects that create
instance that inherit from the class on up to the Object prototype. And
so on. (Once I got my head around Lua concepts, it's remarkable how
easy it was. Code available upon request.)

In the process, I tried to make a OOP system that was better than
Ruby's, by changing two things that have always bothered me. In both
cases, I failed; the reasons why I failed were both "Ah-HA!" moments
for me that gave me insight (I think) into why Ruby is designed as it
is. I share them with you below.


"new" versus "initialize"
---------------------------------------
I was always a little bothered by the fact that when you call "new" on
a class, you define an "initialize" function to handle it. I
mean...wtf, why not just call what you write "new" instead? I was also
annoyed that if you return a specific value from #initialize, it gets
ignored.

I decided that I'd have the user actually write their own "new"
function for the class, and use its return value. In implementation, it
looked something like this:

Rectangle = AKClass:new( )
function Rectangle:new( height, width )
  local theInstance = AKObject:new( self )
  theInstance.height = height
  theInstance.width = width
  return theInstance
end

As I wrote code like that again and again, I realized that in every
'new' function I had to call AKObject:new( self ) to create the
instance, and then return it at the end. I realized that if every class
inherited it's "new" from AKObject, then I could just delegate that
work to AKObject, and let the class just define what to do to the
instance. Suddenly, I had Ruby again, and (now that I'd seen the
alternative) I liked it:

function AKObject.new( owningClass, ... )
  local theInstance = {
    -- Lua stuff for setting up the inheritance here
  }

  if type( owningClass.initialize ) == 'function' then
     owningClass.initialize( theInstance, unpack( arg ) )
     -- No point in using the return value here
  end

  return theInstance
end

function Rectangle:initialize( height, width )
  self.height = height
  self.width = width
end


The Trouble with First-Class Functions
------------------------------------------------------------
I have repeatedly complained on ruby-talk about the fact that Methods
aren't first-class functions. (The term 'first-class functions' as I'm
using it here is another way of saying 'function literals'...it means
that functions are just another atomic variable type, that can be
invoked with any object as the 'self' scope.) Blocks and Procs and
Methods are all different? Bleah! Special-cases are the opposite of
elegant.

Lua is nothing but first-class functions, so I was happy...until I
tried to write a 'super' method to call the method with the same name
on the parent object. Inside a function, I have no idea what that
function is called. So I then tried to write a special-case (urgh!)
"superinit" method specifically for calling parent initializers...and
*that* failed. I finally got to the core of the problem this morning:

function Rectangle:initialize( width, height )
  self.width = width
  self.height = height
end

function Square:initialize( size )
  self.class.superclass.initialize( self, size, size )
end

function UnitSquare:initialize( )
  self.class.superclass.initialize( self, 1 )
end

(For those not familiar with Lua, the colon used when defining a
function means "Hey, please create an implicit first parameter named
'self', because I'm too lazy to type it each time." This is why I can
pass the 'self' from the subclasses to the parent method, and have the
initializer operate on it instead.)

The above works just fine when I create a new Square, but I get some
infinite recursion when I try to create a new UnitSquare. Here's an
English trace of what's happening:

1) AKObject creates a new instance of UnitSquare, and passes that
instance to the UnitSquare initializer.

2) UnitSquare's initializer finds the class of the supplied object
(UnitSquare), it's parent class (Square), and calls that class's
initialize function, passing along the UnitSquare instance.

3) Square's initializer finds the class of the supplied object
(UnitSquare), it's parent class (Square), and...oh hell, we're stuck in
a loop.

The problem is that when I wrote "self.class.superclass" what I
*really* meant was "Hey, I want the superclass of the class that owns
*this method*, not the object that I happen to be operating on."

Which means that methods need to be associated with a class.

Which means that they're not first-class functions.

Aw fuck. Matz is smart. :)

--
(-, /\ \/ / /\/