lua-users home
lua-l archive

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


On Fri, Aug 14, 2009 at 11:02 AM, François Perrad wrote:
> lua-Coat is a Lua 5.1 port of Coat (http://www.sukria.net/perl/coat/),
> a Perl module which mimics Moose (http://www.iinteractive.com/moose/),
> an object system for Perl5 which borrows features from Perl6,
> CLOS (LISP), Smalltalk and many other languages.
> ...The homepage is at http://lua-coat.luaforge.net/,


That seems to have some traction [3-4].

In this syntax:

  require 'Coat'
  class 'Point'
  has( 'x', { is = 'rw', isa = 'number', default = 0 } )
  has( 'y', { is = 'rw', isa = 'number', default = 0 } )
  overload( '__tostring', function (self)
    return '(' .. self:x() .. ', ' .. self:y() .. ')'
  end )
  method( 'draw', function (self)
    return "drawing " .. self._CLASS .. tostring(self)
  end )

the "end )" feels a bit awkward to write for every method in a
program: it's a statement-level keyword (end) contained inside an
expression-level ")", which tend not to mix in Lua.  The "end" and ")"
don't align to their matching start tokens, and the function block has
less indentation than the "function" keyword.  The original also
involves quoting identifiers ('draw').

It could be written in a more luaesque way a follows:

  require 'Coat'
  class 'Point'
  has.x = { is = 'rw', isa = 'number', default = 0 }
  has.y = { is = 'rw', isa = 'number', default = 0 }
  overload.__tostring = function (self)
    return '(' .. self.x .. ', ' .. self.y .. ')'
  end
  method.draw = function (self)
    return "drawing " .. self._CLASS .. tostring(self)
  end
  -- The above can also be written as such:
  -- function method.draw(self)
  --   return "drawing " .. self._CLASS .. tostring(self)
  -- end

where "has", "overload", and "method" are tables, possibly with
__newindex metamethods.

I think self.x rather than self:x() tends to be the preferred syntax
for object properties in Lua.  This requires a proxy table though.

Here's a few initial comments on the source:


> module(..., package.seeall)


I recommend avoiding package.seeall since it pollutes your external interface:

  require "Coat"
  print(Coat.math) --> table: 0x100549c8


> basic_type = type
> local basic_type = basic_type
> local function object_type (obj)
>     local t = basic_type(obj)
>     if t == 'table' and obj._CLASS then
>         return obj._CLASS
>     else
>         return t
>     end
> end
> _G.type = object_type


This breaks type().  Consider:

  require "Coat"
  require "someothermodule"

where someothermodule internally applies type to a read-only table:

  local t = setmetatable({x=1}, {__index=function() error'read only' end})
  assert(type(t) == 'table')

and now fails.


> function _G.class (modname)


This can then imply that other modules in your program cannot
internally use Steve's class.lua module [1].  Consider this:

  -- b.lua
  require "class"   -- internally uses class.lua
  .....

which in turn is used by this:

  -- a.lua
  require "Coat"
  require "b"
  class "a" -- opps, invokes class.lua not Coat.lua

I've had complaints about the Lua module system in the past [2].


> function _G.class (modname)
>     checktype('class', 1, modname, 'string')
>     if _G[modname] then
>         error("name conflict for module '" .. modname .. "'")
>     end


Is there a way to create anonymous classes? or lexically scoped
classes?  For example,

  local class = require "Coat" . class
  local T =
    class(function()
      function method.test() print 'test' end
    end)
  T():test() --> test


[1] http://lua-users.org/wiki/SimpleLuaClasses
[2] http://lua-users.org/lists/lua-l/2009-08/msg00297.html
[3] http://www.iinteractive.com/moose/
[4] http://search.cpan.org/~drolsky/Moose/lib/Moose/Manual/Unsweetened.pod