Page 2 of 2

Re: ClosureClass

Posted: Sat Mar 12, 2011 10:36 pm
by BlackBulletIV
kikito wrote:
BlackBulletIV wrote:Indeed, this is one big problem with closures, instances won't respond if you modify the class, which is a shame.
Are you sure this is a problem due to closure usage? My gut tells me there must be a way to implement indirection with them too.
BlackBulletIV wrote:I'm not sure what you're talking about by copying methods directly to instances. If you're talking about the code the copies stuff from superclass to subclass, that's for inheriting class methods and attributes (and also modules).
I was talking about this code inside _new (pasting below for reference)

Code: Select all

for _, m in pairs(cls.__modules) do
    for name, func in pairs(m) do
      if name ~= 'included' then
        self[name] = function(...) return func(self, ...) end -- get rid of self for the outside world
      end
    end
  end
I'm not sure of what it does - maybe getting rid of the need of using : instead of . ? But then, why doing that only with module methods?
BlackBulletIV wrote:I'm guessing metamethods are copied, I'm not quite sure how it works in MiddleClass (don't you just define an instance function). Anyway, metamethods are yet to be handled.
Metamethods are a bit of a pain on lua when dealing with inheritance. The problem is that Lua doesn't want to use metatables in order to get metamethods: a table must have a __tostring metamethod on its metatable; if its "parent" (the metatable pointed by __index) has a __tostring, Lua doesn't care.

On middleclass I handle this by creating a set of "default metamethods" on every new class. These methods "point" to the methods on the superclass. And if there's no parent, they throw an error, just like a regular method would.
I'm sure there is a way, but it would most likely involve some hardcore table trickery, which I'd have to rack my brain for awhile to figure out.

Oh that code copies module functions from the class into the instance. To maintain consistency it wraps the functions to remove the need of a self parameter. As explained in the recently added README, module functions must have a self parameter because they're not declared inside the initialisation function (the closure), therefore they need a reference to self.

Hmmmm, not quite sure whether I totally understand what you're talking about with metamethods. But I have seen how you make a default implementation which throws an error. But anyway, metamethods aren't implemented yet, they might be soon.

All in all, I think the closure method is not a very good fit for a full OOP system in Lua. But still, I love the style.

Re: ClosureClass

Posted: Sat Mar 12, 2011 10:54 pm
by bartbes
You could get the metatable a metatable. Inception.

Re: ClosureClass

Posted: Sun Mar 13, 2011 12:35 am
by BlackBulletIV
Which problem are you referring to by that?

Re: ClosureClass

Posted: Sun Mar 13, 2011 4:03 am
by tentus
bartbes wrote:You could get the metatable a metatable. Inception.
I just rewatched that tonight with my younger bro, who missed it when it came out. Enjoyable film.

Re: ClosureClass

Posted: Sun Mar 13, 2011 4:44 am
by BlackBulletIV
Oh, you're talking about a movie. Ok.

Re: ClosureClass

Posted: Sun Mar 13, 2011 9:17 am
by bartbes
It's a real option though, getting a metatable with an __index metafield set to the parent's metatable.

Re: ClosureClass

Posted: Mon Mar 14, 2011 1:44 am
by appleide
Tangent.
Recently, I've started to use classes implemented by the following code.

Code: Select all

function class(parent)
  local new = {}
  for k, v in pairs(parent or {init=function() end}) do
    new[k] = v
  end
  new.__super, new.__index = parent, new
  return setmetatable(new, {__call = function(t , ...) 
    local instance=setmetatable({__class = new}, new);
    new.init(instance, ...)
    return instance
  end})
end
Child classes are copies of parent classes.
To instantiate a class, simply call it. e.g. local myvector = vector(x, y)
Classes are the instances metatables, so you can write a method class:__add to overload the + operator.

Code: Select all

style = class()

--- Initiates a style instance.
-- @param tags A string of whitespace separated tags.
-- @param styles A table of key-value style attributes. 
function style:init(tags, styles)
  self.tags = sorttags(tags)
  self.styles = {}
  self.owner = nil
  for k, v in pairs(styles) do
    self.styles[k] = v
  end
  self:compute()
end

--- Compute styles. E.g. borderleftwidth and borderwidth
function style:compute()
  local this = self.styles
  -- ...more code... --
end

Re: ClosureClass

Posted: Mon Mar 14, 2011 3:27 am
by BlackBulletIV
That looks like a largely simplified version of MiddleClass to be (in the result anyway). The big thing it lacks, which I would not like to be without, is mixins.

Re: ClosureClass

Posted: Mon Mar 14, 2011 12:22 pm
by kikito
Robin wrote:
kikito wrote:Metamethods are a bit of a pain on lua when dealing with inheritance. The problem is that Lua doesn't want to use metatables in order to get metamethods: a table must have a __tostring metamethod on its metatable; if its "parent" (the metatable pointed by __index) has a __tostring, Lua doesn't care.
That is because

Code: Select all

mt.__index = t -- where mt is the metatable of some other table and t is yet another table
is really a shortcut for

Code: Select all

mt.__index = function (table, key) return t[key] end
Thus t is really not a "parent" of whatever uses mt as metatable, it's just a place to get values for missing keys from.
I know that. The problem is that Lua uses something equivalent to rawget(getmetatable(t), '__tostring') instead of using t.__tostring to get a metamethod. They are not "looked up through __index". So the only option left is creating "fake" metamethods that do that extra bit of work.