lua-users home
lua-l archive

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


Hi guys,

On Fri, Oct 1, 2010 at 6:02 AM, steve donovan <steve.j.donovan@gmail.com> wrote:
> On Fri, Oct 1, 2010 at 10:27 AM, Miles Bader <miles@gnu.org> wrote:

>> fact that it adds more "magic" makes me take take pause; it feels like
>> something that might be one of those "good ideas" which seems
>> appealing at first, but turns out to be a ball of hair in the long
>> run.
>
> I'm with you on that;  there are remarkably few gotchas in Lua.  A
> well-written library will know that people will make a dot/colon
> confusion and will be able to issue a 'bad self' message - maybe even
> say 'you forgot the colon!'
>

Sorry. I swear I've tried to keep silent but I think that I have the
duty to clarify misunderstood concepts about the patch.

Please, watch the examples below (sent to me by a PenPal):

Super = {
       new = function (o)
               o = o or {}
               o.x = 10 -- constant default
               return o
       end,
}
Sub = setmetatable({}, { __index = Super})
function Sub:new (o)  -- COLON (syntactic sugar)
       o = Super.new () -- DOT. COLON will fail
       o.y = 2 -- DOT
       return o
end
o1 = Sub.new() -- DOT
print(o1.x, o1.y) -- DOT

If you add an "class" default_x , it should be changed to:

Super = {
       default_x = 10,
       new = function (self, o)  -- Cannot you colon
               o = o or {}
               o.x = self.default_x -- "class" default
               return o
       end,
}
Sub = setmetatable({}, { __index = Super})
function Sub:new (o)  -- COLON (syntactic sugar)
       o = Super:new (o) -- now COLON is OK
	   -- but could be o = Super.new(Super,o)  -- DOT
       o.y = 2 -- DOT
       return o
end
o1 = Sub.new() -- DOT
print(o1.x, o1.y) -- DOTs

Note that "new" acts like a "constructor" but not a classical one
because constructors usually can be seen as a special METHOD of a
class and therefore should receive the CLASS as the self, as became
necessary in ** part ** of example 2. As Lua gives you the power to
make it in different ways, people use it.

Now, suppose you *** chose *** to use a consistent OO Java-like
approach in your brand new Lua software. How OOBit could help?

Super = {
       default_x = 10,
       new = method (o)  -- class method
               o = o or {}
               o.x = self.default_x -- Self is the Class
               return o
       end,
}
Sub = setmetatable({}, { __index = Super})
method Sub.new (o)  -- DOT
       o = Super.new (o) -- DOT
       o.y = 2 -- DOT
       return o
end
o1 = Sub.new() -- DOT
print(o1.x, o1.y) -- DOT

As OOBit offers you a way to consistently use of the DOT, it drives
you gently to a conventional-Java-style OO usage, as you can see
above, where all constructors seem to be naturally used as class
methods.

If you ** chose ** to work using a Java like OO approach, you ** may**
let the patch help. Believe, it will help a lot.

If you prefer a "classical" approach in your projects, just do not
create METHODs. You will never know that OOBit exists.

And don't worry too much about performance impact. I already have a
alpha version running and the impact on performance is negligible -
mainly in function calls with some parameter passing. You may
benchmark it later when I release the beta. Lua's runtime is
remarkably simple and beautifully efficient, which helps a lot. ** I
would like some help in varargs stack handling **.

By the way, OOBit does not require a keyword like METHOD. It is just a
syntactic sugar:
  method a.b( etc) ... end  <=>   function a.b (self, etc ) ...end;
a.b = ooset(a.b)

I use the keyword because I think it is more compact and quite
expressive. I could have used a double colon " :: " as a ** super
syntactic sugar **, for example.

And finally, when your project needs to call a "classic" library, you
must use the notation recommended by the library's manual. OOBit does
not interfere with non "ooseted" functions.

I think that incompatibilities could arise only when:
a) you pass a new METHOD that you written to a classical library and
b) internally, the classical library make one of these kinds of call
   - obj.METHOD(obj, etc) meaning " obj:METHOD(etc) " or " METHOD(obj,etc) "
   - obj.METHOD(obj2,etc) meaning " tmp = obj.METHOD; tmp(obj2,etc) "

I believe this would rarely occur (If you are a library writer, you
could help a eventual community of OOBits users avoiding constructions
like these).

To solve these kind of incompatibility, you could encapsulate the function:

Consider the "demanding'" library function: " library_function(func) "

To use it you could write
  library_function(function(...) return your_method(...) end)

or create a permanent encapsulated
  a_compatible = function(...) return your_method(...) end
and then call
  library_function(a_compatible)

I implemented OOBit in a different way, but If necessary I could
return to the original idea to may do:

  a_compatible = oounset(your_method)

As a simple assignment that clears the OOBit on value your_method
before assign it to a_acompatible.

It's also possible to create a way to mark "demanding"  functions,
although it will increase a little bit the execution time. In that
case, you could just execute:

  ooclassic(library_function)

Now, the patch will ignore the OOBit status during a library_function
call, so you could do:

  library_function( your_method )

with no worries.

But remember, it would be necessary to occur (a) and (b) to have to
handle this kind of problem.

Sorry if this message still contains any errors. I limited the number
of reading and revision in five.
As I always guard against the Shakespeare's language, I apologize in
advance.  :-)

Cheers,

Nilson