lua-users home
lua-l archive

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


On Tue, Mar 19, 2013 at 11:29 AM, Ross Bencina <rossb-lists@audiomulch.com> wrote:
(...)
It looks as though using the metatable is substantially more memory efficient than copying method references into each object instance, which makes sense. On the other hand, invoking methods via the metatable looks to be about 5% slower than if they were stored in the object's table (I guess the cost of an indirection will never be 0).

For my applications, memory often matters more than performance, which probably often means metatables. 

I am not interested in full-fledged OO (no information hiding, no polymorphism, ...), I only want a memory-efficient and simple way of associating methods to objects.  

...And I don't want to wrap my head every time around metatables and __index :-)   so I came up with the following 'class' definition:

   local class = { };  setmetatable(class, class)
   function class.__call(c, t)
      local obj = setmetatable(t or {}, c)
      if c == class then obj.__index = obj end
      return obj
   end

All the "magic" is encapsulated once in the snippet above.
Now I can easily define "classes" and use instances:
  
   stack = class()
   -- let's define stack methods
   function stack.push(self, e)  table.insert(self, e)  end
   function stack.pop(self)   return table.remove(self)  end

   -- let's use a stack:
   s = stack()  -- an empty stack
   s:push(12)
   print(s:pop())

A stack with an already initialized state could be defined as:
   s = stack{11, 22, 33} 
   -- (actually passing the state to the "constructor")

If some "class" needs some work at instantiation time, I just usually define an init() method:

   function stack.init(self, fancyparam) 
      . . . -- perform some instance initialization 
      return self 
   end
  
   s2 = stack():init("fancy stuff")

I found that I usually needed no initialization -- just passing a table was ok.  but should it be required more often, it is easy to modify the class.__call() definition above:

   function class.__call(c, ...)
      local obj = setmetatable(t or {}, c)
      if c == class then obj.__index = obj end
      if c.init then c.init(obj, ...) end
      return obj
   end

In that case, arguments to the "constructor" are passed to an init() method if it exists.

HTH

Phil