Well, I recently (very recently) started to play around with Lua. I ordered the book before leaving to Colombia and found it when I was back. It took me just a day to read it, as the book is a light read and rather well-written, covering all the important topics.
One reason I’ve started to look at Lua is because it seems like a rather powerful language. Read more if you’re interested in why, and a first OO-system that I’ve rolled in it.
Powerful is a rather abstract word, and perhaps I should first explain why I consider Lua, powerful, especially since I come from a rather different programming language sphere (Haskell).
The reason that lua appeals to me is that it seems to enable a way of meta-programming that cuts cleanly through your code. It takes a scheme-approach of being built-up in an orthogonal manner with a small core. That being said, I find it more appealing than scheme as, at least to me, it is easier to code things in. The meta-programming seems to be more powerful than in scheme.
Anyways, I started coding in it yesterday, wanting to roll an OO-system that would be easy to use. Additionally, I wanted a way to nicely dump my state and then be able to reload it after potentially modifying some of the classes I use.
For the serialization aspect, I took the serialization scheme from the Lua Book and extended it to deal with custom serialization meta-methods as well as the possibilities of keys being tables. Note that it’s not yet finished, it need a small piece of code to generate unique names, but that’s rather trivial.
As for the OO system, this is a second version. My original version was rather primitive. One thing that I wanted was the ability to call the static-super method of a method. Now a simple way would be:
function Class:method(...) SuperClass.method(self, ....) end
I did not like this idea, however, as it requires explicitly referring to the super-class. Certainly, for simple class-trees this is a viable option. However, since I would like to introduce the concept of mixins, and in general don’t like the verbositoy of this, I introduced a ‘static’ way of defining __super (The super-method). Basically, whenever a method is defined, it’s function-environment is modified to have a link to __super (as well as __class). The reason for having a link to __class is that this is the static-class that the method belongs to, not the class of the object.
The (unfinished) code can be seen below. It is based on ideas from: ClassesAndMethodsExample and InheritanceTutorial. As mentioned before, this is only my second day of hacking Lua, so I’m certain there are things that could be done much better. Suggestions, as always, welcome
local setmetatable = setmetatable -------------------------------------------------------------------------------- -- Helper functions: -------------------------------------------------------------------------------- function memoize(f) local self = setmetatable({}, {__mode = "k"}) self.__index = function(self, k) local v = f(k); self[k] = v return v end self.__call = function(self, k) return self[k] end return self end -------------------------------------------------------------------------------- -- Class System -------------------------------------------------------------------------------- -- Methods should be called on the klass object with as parameter the object itself! -- Root = { super = nil; name = "Root"; new = function(class, ...) local obj = {class = class} local meta = { __index = class.methods, __serialize = class.__serialize or Root.__serialize } setmetatable(obj, meta) if (class.methods.init) then class.methods.init(obj, ...) end return obj end; methods = { classname = function(self) return (self.class.name) end; isa = function(self, aClass) local cur_class = self.class while (nil ~= cur_class) do if cur_class == aClass then return true else cur_class = cur_class.super end end return false end }; data = {}; __serialize = function(self, serializer, name) serializer:write("setmetatable({class = " .. self:classname() .. "}, {\n") serializer:write(" __index = " .. self:classname() .. ".methods,\n") serializer:write(" __serialize = " .. self:classname() .. ".__serialize or Root.__serialize\n") serializer:write("})\n") for k,v in pairs(self) do -- save its fields if k ~= "class" then local kname if serializer:isBasic(k) then kname = serializer:basicSerialize(k) elseif type(k) == "table" then if saved[k] then kname = saved[k] else kname = serializer:generateName() serializer:serialize(kname, k) end end local fname = string.format("%s[%s]", name, kname) serializer:serialize(fname, v) end end end } function Class(name, super) super = super or Root class = { super = super, name = name, methods = {} } -- if class slot unavailable, check super class -- if applied to argument, pass it to the class method new setmetatable(class, { __index = super, __call = function(self,...) return self:new(...) end }) setmetatable(class.methods, { -- if instance method unavailable, check method slot in super class __index = class.super.methods, -- when defining a new method, set the environment for proper, static, class access and super-method access __newindex = function (c, m, f) if (class.super.methods[m]) then setfenv(f, setmetatable({__class = class, __super = class.super.methods[m]}, {__index = getfenv(f) })) else setfenv(f, setmetatable({__class = class}, {__index = getfenv(f) })) end rawset(c,m,f) end }) return class end function Mixin(name, mixin, super) -- return (name, nil, super) end function Singleton(name, super) end -------------------------------------------------------------------------------- -- Serializer -- TODO: Make a way to easily define what attributes -not- to save -------------------------------------------------------------------------------- Serializer = Class("Serializer") function Serializer.methods:init(stream, temp, saved) self.stream = stream or io.stdout self.temp = temp or 0 self.saved = saved or {} end function Serializer.methods:basicSerialize(value) if type(value) == "boolean" then return tostring(value) elseif type(value) == "number" then return tostring(value) elseif type(value) == "string" then return string.format("%q", value) end end function Serializer.methods:isBasic(value) return type(value) == "boolean" or type(value) == "number" or type(value) == "string" end function Serializer.methods:write(...) self.stream:write(...) end function Serializer.methods:serialize(name, value) self:write(name, " = ") if self:isBasic(value) then self:write(self:basicSerialize(value), "\n") elseif type(value) == "table" then if self.saved[value] then -- value already saved? self:write(self.saved[value], "\n") -- use its previous value else self.saved[value] = name -- save name for next time serializer = (getmetatable(value) or self).__serialize or self.__serialize serializer(value, self, name) end else error("cannot save a " .. type(value)) end end function Serializer.methods:__serialize(serializer, name) serializer:write("{}\n") -- create a new table for k,v in pairs(self) do -- save its fields local kname if serializer:isBasic(k) then kname = serializer:basicSerialize(k) elseif type(k) == "table" then if saved[k] then kname = saved[k] else kname = serializer:generateName() serializer:serialize(kname, k) end end local fname = string.format("%s[%s]", name, kname) serializer:serialize(fname, v) end end function deserialize(o, stream) stream = stream or io.stdin end -------------------------------------------------------------------------------- -- Test Cases -------------------------------------------------------------------------------- Foo = Class("Foo") function Foo.methods:init(...) self.foo = 1 end function Foo.methods:__serialize(serializer, name) serializer:write("{foo = " .. self.foo .. "}\n") end Bar = Class("Bar", Foo) function Bar.methods:init(...) __super(self, ...) self.bar = 2 end function Bar.methods:boom() if __super then __super(self) end print "Bar:boom" end Bum = Class("Bum", Bar) function Bum.methods:init(...) if __super then __super(self, ...) end self.bum = 3 end function Bum.methods:boom() if __super then __super(self) end print "Bum:boom" end

With the help of debug library it is possible to achieve even shorter syntax:
function Child:method(…)
super(…)
end
still such approach is rather slow (it requires one closure creation per call).
Also take a look at metalua. It enables rather powerful techniques: e.g. one can make an extension that `saves` function body AST somewhere and this allows to get pretty OO-syntax at virtually no cost.