lua-users home
lua-l archive

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


Hi guys!

I just created a neat little object system for Lua (5.1) that does pretty much exactly what I want.

You use it like this:

newThing = object(function() -- could add arguments here too
  var1 = 1
  local var2 = 'test'

  function method1()
    var1 = var1+1
  end

  local function method2()
    return string.sub(var2, 2)   -- can use globals as normal
  end
end)

thing = newThing()
thing.var1 = 5
thing.method1()   -- yeah, just dot, no colon

The point is: You just put all fields and methods inside one big definition function. What you declare 'local' will be private; everything else will become part of the object.

The great advantage: No need to ever write 'self.'. (I'm coming from the Java world and I just hate having to insert 'self' all the time (or at all).)

Also, all non-local variables are both readable and writeable from outside.

Usually I write a module 'plain' first (everything top-level) and decide to make it an object later. With this system, I can do that without changing one bit in the code.

There is one little caveat: The definition function must not be recursive (making more objects of its own kind); that would probably break the setfenv trickery. Making more objects within methods is fine.

Here's how it is implemented. Attention, it's short - 14 lines with comments and whitespace :)

*****
-- make an object from a definition function.
-- all variables and functions declared in the definition function without 'local'
-- are automatically part of the new object.
function makeObject(definition, ...)
  -- make an environment that inherits all the globals
  local env = setmetatable({}, {__index = function(_, k) return _G[k] end})   
  setfenv(definition, env)(...)
  return env
end

-- the beloved curry operator (for one fixed arg)
function curry(f, a) return function(...) return f(a, ...) end end

function object(definition) return curry(makeObject, definition) end
*****

You can also put it all in one function, but it still ends up taking 7 LoC:

***
function object(def)
  return function(...)
    local env = setmetatable({}, {__index = function(_, k) return _G[k] end})   
    setfenv(def, env)(...)
    return env
  end
end
***

Is this old? Is this new? Has this been done before? I love this and I think I'll be using it to death. :)

Cheers,
Stefan