lua-users home
lua-l archive

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

great trick

honestly, i prefer the way that javascript does.

but the lua way is not bad :-)
easy to keep c-api and lua-api in the same style.

于 2011-11-20 20:27, Stefan Reich 写道:
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

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

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

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

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