what to make of this fellow named __ipairs?

classic Classic list List threaded Threaded
20 messages Options
Reply | Threaded
Open this post in threaded view
|

what to make of this fellow named __ipairs?

David Manura
What are we to make of this fellow named __ipairs in 5.2.0-alpha?

The Reference Manual specifies the mechanics of `__ipairs` [1] but not
its intended purpose.  This leads to many questions....  How should
`ipairs(t)` behave if `t` represents a sparse array? a 0-indexed
array? an instance of an OO class?  Should the keys always be numbers?
integers? returned in a particular order?  What should we do if we
need both forward and reverse iterators for an object?  Similarly, for
`__pairs`, it may tell you in arbitrary order the values of `k` such
that `o[k]` is defined (e.g. methods and fields), or perhaps it tells
you other values of `k` not exposed via the indexing operator (e.g.
things conceptually contained in the object).  Due to this ambiguity,
for arbitrary objects `__pairs` may best be limited to introspection
or debugging purposes, like how `__tostring` is often not intended for
the rigors of serialization.  For some custom object I probably would
just create my own iterator with its own more descriptive name.

At one point `ipairs(t)` was redefined in terms of `for i=1,#t`, but
this was rejected [2].  Perhaps that is good for cases where you don't
want to start at 1 or stop at #t or when random access may be
inefficient (linked list).

One motivation for `__ipairs` is to allow a piece of code to be
polymorphic.  `f(t)` will work identically regardless whether `t` is a
raw table, proxy, or userdata.  However, this doesn't work in
practice.  table functions ignore metamethods.  Even `next` ignores
metamethods, and `next` is arguably as important for hash tables as
'#' is for array tables since `next(t) == nil` is a common idiom to
test for the null set.   Then some have specifically asked for
`rawlen` and `rawtostring`, adding to the quagmire.

A reason we write `ipairs(t)` in the first place is that it's not
always suitable *in general* to make it a method, `t:ipairs()`, as we
might do in other languages.  In Lua, `t:ipairs`'s existence implies
`t.ipairs ~= nil` and `t["ipairs"] ~= nil`.  Therefore, we make it
instead a *meta*-method `__ipairs`, which `ipairs` uses to achieve a
polymorphism similar to a method call.  IMO, maybe what we need, more
generally, is a more convenient notation to call metamethods, as
opposed to `for k,v in getmetatable(o).__pairs(o) do ...`.  Most of
the time, however, it is just fine to expose the iterator through a
regular method, conveniently attached to the object, so we have
`o:iter()` for some custom object `o`.  Also, in Lua you can always do
things like `local ipairs = myipairs; for i,v in ipairs(t) do ...`.

On performance, __ipairs could slow down iterations, although my test
below indicates it doesn't really.  At the very least, it slightly
complicates the implementation and human interpretation.

  local t = {}; for i=1,1000 do t[i]=i end
  for j=1,100000 do
    for i,v in ipairs(t) do end
  end

Finally, `pairs` and `ipairs` are not essential functions, so we could
avoid the issue by just eliminating them (although that was tried and
rejected [3]).  Anything you can do with these can also be done via
`next` and `rawget`.  The only reason I sometimes use `ipairs` is that
code is a bit shorter than using `#` even though less optimal.
`pairs` can always be replaced with `next`.

So, `__ipairs` leaves me a little perplexed.

[1] http://www.lua.org/work/doc/manual.html#pdf-ipairs
[2] http://lua-users.org/lists/lua-l/2010-08/msg00011.html
[3] http://lua-users.org/lists/lua-l/2010-05/msg00416.html

Reply | Threaded
Open this post in threaded view
|

Re: what to make of this fellow named __ipairs?

steve donovan
On Thu, Jan 27, 2011 at 8:42 AM, David Manura <[hidden email]> wrote:
> The Reference Manual specifies the mechanics of `__ipairs` [1] but not
> its intended purpose.

Interesting points!  If I see ipairs(), I expect an array-like
iteration with integer indices in ascending order, although not
_necessarily_ a contiguous sequence in the case of a sparse array.
Otherwise, since we have __len and __index, there would be no point in
__ipairs since the numeric for is clearer in most cases (although not
more efficient in the case of a proxy table)

__ipairs means that ipairs can be trained to go over
arrays-with-holes, which can be useful.

The general virtualization problem for tables remains vexing.

steve d.

Reply | Threaded
Open this post in threaded view
|

Re: what to make of this fellow named __ipairs?

Dirk Laurie
In reply to this post by David Manura
On Thu, Jan 27, 2011 at 08:42:32AM +0200, David Manura wrote:
>
> The Reference Manual specifies the mechanics of `__ipairs` [1] but not
> its intended purpose.  

I use it exclusively as a hack that allows `for` loops to work with
proxy tables too.  Thus:

    __pairs = function(t) return pairs(t[index]) end;
    __ipairs = function(t) return ipairs(t[index]) end;

Dirk


Reply | Threaded
Open this post in threaded view
|

Re: what to make of this fellow named __ipairs?

Axel Kittenberger
In reply to this post by David Manura
For your 'objects' you can make ipairs mean whatever you want it to.
Sticking with the default meaning (e.g. for proxy tables) should be
prefered coding style since the reader/maintainer familiar with Lua
will expect it to work that way.

The right to exist for ipairs is an easy case. Default ipairs is well
defined to be unequivocal for any table whereas default len is not.

Missing __next is a pity for complete virtualisation/proxies.

Reply | Threaded
Open this post in threaded view
|

Re: what to make of this fellow named __ipairs?

steve donovan
On Thu, Jan 27, 2011 at 10:20 AM, Axel Kittenberger <[hidden email]> wrote:
> For your 'objects' you can make ipairs mean whatever you want it to.
> Sticking with the default meaning (e.g. for proxy tables) should be
> prefered coding style since the reader/maintainer familiar with Lua
> will expect it to work that way.

Yes, both the beauty and the pain of dynamic languages comes from
interfaces being 'underspecified'.

There is a mechanism, then we have to choose policy.

__next meaning overriding the meaning of next()?  It could go further
and modify pairs() behaviour as well, but that might have performance
implications (there's always that trade-off)

steve d.

Reply | Threaded
Open this post in threaded view
|

Re: what to make of this fellow named __ipairs?

Stuart P. Bentley
In reply to this post by David Manura
?>Finally, `pairs` and `ipairs` are not essential functions, so we could
>avoid the issue by just eliminating them (although that was tried and
>rejected [3]).

I once again raise the suggestion of making ipairs- and pairs- functionality
2 more types of for loop ('for i, v over t do' and 'for k, v of t do'), with
the former using 'local i,v=1 while t[i] do k=t[i] <...> i=i+1 end'
semantics and the latter using 'local k,v = next(t) while t[k] do v=t[k]
<...> k=next(t,k) end'.

Also, shouldn't next(), pairs(), and ipairs() technically go in the "table"
library with unpack()?


Reply | Threaded
Open this post in threaded view
|

Re: what to make of this fellow named __ipairs?

Tony Finch
In reply to this post by David Manura
On Thu, 27 Jan 2011, David Manura wrote:

>
> A reason we write `ipairs(t)` in the first place is that it's not
> always suitable *in general* to make it a method, `t:ipairs()`, as we
> might do in other languages.  In Lua, `t:ipairs`'s existence implies
> `t.ipairs ~= nil` and `t["ipairs"] ~= nil`.  Therefore, we make it
> instead a *meta*-method `__ipairs`, which `ipairs` uses to achieve a
> polymorphism similar to a method call.  IMO, maybe what we need, more
> generally, is a more convenient notation to call metamethods, as
> opposed to `for k,v in getmetatable(o).__pairs(o) do ...`.  Most of
> the time, however, it is just fine to expose the iterator through a
> regular method, conveniently attached to the object, so we have
> `o:iter()` for some custom object `o`.  Also, in Lua you can always do
> things like `local ipairs = myipairs; for i,v in ipairs(t) do ...`.

One of the significant oddities in Lua is the distinction between methods
called using the : operator and metamethods called by the language runtime
and some library functions. It is a scruffy mixture of the prototype and
class styles of OOP. David's observations about __ipairs are a good
example of the untidyness.

I think the language would be neater if the method / metamethod
distinction could be reduced or removed. It can be done reasonably nicely,
I think, in a way that supports prototype-style and class-style OOP.
However I don't think it can keep backwards compatibility without
sacrificing efficiency. The key change is a version of the old idea of
making the lookup algorithm for : different from . which allows more
natural support for class-style OOP by making it easy to separate instance
variables from methods.

Method calls on tables without metatables work as at present. If the table
has a metatable the method is looked up in the metatable (instead of the
table itself). If that fails the lookup falls back to a __method
metamethod analogous to the __index metamethod.

For prototype-style OOP,

        function new(prototype)
                local t = { __index = prototype, __method = prototype }
                return setmetatable(t,t)
        end

For class-style OOP,

        MyClass = { --[[ methods ]] }
        function new(class)
                return setmetatable({}, class)
        end

You get roughly the existing Lua behaviour with

        local t = { .... }
        local mt = { __method = t, .... }
        setmetatable(t, mt)

except that there's no fallback through __index and unknown methods cause
an loop exception instead of an attempt to call nil. Perhaps this setup
could be special-cased to index the table in the current manner... I tend
to think that these caveats are a result of Lua's current semantics being
weird :-)

I note that making methods and metamethods more similar is likely to lead
to Python-style underscore-heavy __magic__ methods, though in Lua they
are asymmetrically __magic.

Tony.
--
f.anthony.n.finch  <[hidden email]>  http://dotat.at/
HUMBER THAMES DOVER WIGHT PORTLAND: NORTH BACKING WEST OR NORTHWEST, 5 TO 7,
DECREASING 4 OR 5, OCCASIONALLY 6 LATER IN HUMBER AND THAMES. MODERATE OR
ROUGH. RAIN THEN FAIR. GOOD.

Reply | Threaded
Open this post in threaded view
|

Re: what to make of this fellow named __ipairs?

Javier Guerra Giraldez
On Thu, Jan 27, 2011 at 9:43 AM, Tony Finch <[hidden email]> wrote:
> Method calls on tables without metatables work as at present.

at present, there are no 'method calls on tables'  they're just calls
to table items that happen to be functions.

your proposal would mean the language have to distinguish the 'kind'
of lookup according to the 'intent': was it a 'simple' table lookup?
is it a 'method call'? is that table a metatable, so we need 'simple'
semantic even if we intend to call the method?

i _vastly_ prefer to have well-specified semantics.  the difference
between '.' and ':' is a feature, not a kludge, it allows the
programmer (not some confusing context rules) to specify exactly what
semantic it needs.

--
Javier

Reply | Threaded
Open this post in threaded view
|

Re: what to make of this fellow named __ipairs?

Tony Finch
On Thu, 27 Jan 2011, Javier Guerra Giraldez wrote:
>
> your proposal would mean the language have to distinguish the 'kind'
> of lookup according to the 'intent': was it a 'simple' table lookup?
> is it a 'method call'?

Yes. This distinction already exists in the syntax (. vs :) and in the
implementation (GETTABLE vs SELF).

Tony.
--
f.anthony.n.finch  <[hidden email]>  http://dotat.at/
HUMBER THAMES DOVER WIGHT PORTLAND: NORTH BACKING WEST OR NORTHWEST, 5 TO 7,
DECREASING 4 OR 5, OCCASIONALLY 6 LATER IN HUMBER AND THAMES. MODERATE OR
ROUGH. RAIN THEN FAIR. GOOD.

Reply | Threaded
Open this post in threaded view
|

Re: what to make of this fellow named __ipairs?

Edgar Toernig
In reply to this post by Tony Finch
Tony Finch wrote:
>
> One of the significant oddities in Lua is the distinction between methods
> called using the : operator and metamethods called by the language runtime
> and some library functions.

Indeed.

> However I don't think it can keep backwards compatibility without
> sacrificing efficiency. The key change is a version of the old idea of
> making the lookup algorithm for : different from . which allows more
> natural support for class-style OOP by making it easy to separate instance
> variables from methods.

Not only instance variables, data too (if the instance is the container
for arbitrary data).

I'm advocating for a change to the colon operator for nearly 10 years[1]
and I've given up by now.

Ciao, ET.

[1] i.e. http://lua-users.org/lists/lua-l/2001-11/msg00459.html

Reply | Threaded
Open this post in threaded view
|

Re: what to make of this fellow named __ipairs?

joao lobato
On 1/27/11, E. Toernig <[hidden email]> wrote:

> Tony Finch wrote:
>>
>> One of the significant oddities in Lua is the distinction between methods
>> called using the : operator and metamethods called by the language runtime
>> and some library functions.
>
> Indeed.
>
>> However I don't think it can keep backwards compatibility without
>> sacrificing efficiency. The key change is a version of the old idea of
>> making the lookup algorithm for : different from . which allows more
>> natural support for class-style OOP by making it easy to separate instance
>> variables from methods.
>
> Not only instance variables, data too (if the instance is the container
> for arbitrary data).
>
> I'm advocating for a change to the colon operator for nearly 10 years[1]
> and I've given up by now.
>
> Ciao, ET.
>
> [1] i.e. http://lua-users.org/lists/lua-l/2001-11/msg00459.html
>
>

What about the case when wants to discover the method name at runtime:

instance:method(args) -- okay, __method

local someMethod = 'method'
instance[someMethod](instance,args) -- __index or __method?

Tables are associative arrays with a few tricks to allow them to serve
has building blocks:
 - the dot syntax allows them to look like structs or namespaces (but
fails on the infamous bit.and);
 - the colon syntax allows them to look like objects (but fails on the
reflection example);
 - the {1,2,3} constructor, # and the underlying "implementation
detail" allow them to look like arrays (but fail regarding nil - which
was always meant to be a "non value" anyway);
 - __pairs and __ipairs exist only to make them better (more
transparent) proxies (but apparently __next is missing);
 - __call allows them to be... functors?

In a way, Lua as a whole follows the same principle as its tables:
it's a clean and enjoyable imperative language with a side of:
 - data description language (tables again :));
 - full-featured functional language;
 - pretty nice OOP language (class or prototype, you choose);

In the end, those metamethods are a distinguishing feature while
method calling through : is syntactic sugar.

I guess I got a bit philosophical, my point is that, in my opinion, if
one mixes container data with methods, it looks like bad design.

Reply | Threaded
Open this post in threaded view
|

Re: what to make of this fellow named __ipairs?

Tony Finch
On Fri, 28 Jan 2011, joao lobato wrote:
>
> What about the case when wants to discover the method name at runtime:

It may be worth allowing obj:[method](args)

> I guess I got a bit philosophical, my point is that, in my opinion, if
> one mixes container data with methods, it looks like bad design.

Yes. I would like it to be easier and more efficient to do that.

Tony.
--
f.anthony.n.finch  <[hidden email]>  http://dotat.at/
HUMBER THAMES DOVER WIGHT PORTLAND: NORTH BACKING WEST OR NORTHWEST, 5 TO 7,
DECREASING 4 OR 5, OCCASIONALLY 6 LATER IN HUMBER AND THAMES. MODERATE OR
ROUGH. RAIN THEN FAIR. GOOD.

Reply | Threaded
Open this post in threaded view
|

Re: what to make of this fellow named __ipairs?

Alexander Gladysh
On Fri, Jan 28, 2011 at 16:52, Tony Finch <[hidden email]> wrote:
> On Fri, 28 Jan 2011, joao lobato wrote:

>> What about the case when wants to discover the method name at runtime:

> It may be worth allowing obj:[method](args)

I certainly miss this feature often. Is it hard to implement?

Alexander.

Reply | Threaded
Open this post in threaded view
|

Re: what to make of this fellow named __ipairs?

Roberto Ierusalimschy
> On Fri, Jan 28, 2011 at 16:52, Tony Finch <[hidden email]> wrote:
> > On Fri, 28 Jan 2011, joao lobato wrote:
>
> >> What about the case when wants to discover the method name at runtime:
>
> > It may be worth allowing obj:[method](args)
>
> I certainly miss this feature often. Is it hard to implement?

Just write obj[method](obj, args).

-- Roberto

Reply | Threaded
Open this post in threaded view
|

Re: what to make of this fellow named __ipairs?

Alexander Gladysh
On Fri, Jan 28, 2011 at 18:50, Roberto Ierusalimschy
<[hidden email]> wrote:
>> On Fri, Jan 28, 2011 at 16:52, Tony Finch <[hidden email]> wrote:
>> > On Fri, 28 Jan 2011, joao lobato wrote:

>> >> What about the case when wants to discover the method name at runtime:

>> > It may be worth allowing obj:[method](args)

>> I certainly miss this feature often. Is it hard to implement?

> Just write obj[method](obj, args).

Well, I know that, thanks.

I miss obj:[method](args) when obj is an expression (say, a function
call). I have to create a temporary variable then, and it is a bit
ugly.

Nothing serious, of course, but obj:[method](args) looks more
aesthetically pleasing to me...

Alexander.

Reply | Threaded
Open this post in threaded view
|

Re: what to make of this fellow named __ipairs?

Tony Finch
In reply to this post by Alexander Gladysh
On Fri, 28 Jan 2011, Alexander Gladysh wrote:
> On Fri, Jan 28, 2011 at 16:52, Tony Finch <[hidden email]> wrote:
>
> > It may be worth allowing obj:[method](args)
>
> I certainly miss this feature often. Is it hard to implement?

Something like this:

diff --git a/src/lcode.c b/src/lcode.c
index 6194749..adbe971 100644
--- a/src/lcode.c
+++ b/src/lcode.c
@@ -500,12 +500,17 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
 }


-void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
+int luaK_self1 (FuncState *fs, expdesc *e) {
   int func;
   luaK_exp2anyreg(fs, e);
   freeexp(fs, e);
   func = fs->freereg;
   luaK_reserveregs(fs, 2);
+  return func;
+}
+
+
+void luaK_self2 (FuncState *fs, int func, expdesc *e, expdesc *key) {
   luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key));
   freeexp(fs, key);
   e->u.s.info = func;
diff --git a/src/lcode.h b/src/lcode.h
index b941c60..4aaeb01 100644
--- a/src/lcode.h
+++ b/src/lcode.h
@@ -55,7 +55,8 @@ LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
 LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
 LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
 LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e);
-LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
+LUAI_FUNC int luaK_self1 (FuncState *fs, expdesc *e);
+LUAI_FUNC void luaK_self2 (FuncState *fs, int func, expdesc *e, expdesc *key);
 LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
 LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
 LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
diff --git a/src/lparser.c b/src/lparser.c
index 7ff0925..c684a78 100644
--- a/src/lparser.c
+++ b/src/lparser.c
@@ -778,10 +778,15 @@ static void primaryexp (LexState *ls, expdesc *v) {
         break;
       }
       case ':': {  /* `:' NAME funcargs */
+        int func;
         expdesc key;
         luaX_next(ls);
-        checkname(ls, &key);
-        luaK_self(fs, v, &key);
+        func = luaK_self1(fs, v);
+        if (ls->t.token == '[')
+          yindex(ls, &key);
+        else
+          checkname(ls, &key);
+        luaK_self2(fs, func, v, &key);
         funcargs(ls, v);
         break;
       }


Tony.
--
f.anthony.n.finch  <[hidden email]>  http://dotat.at/
HUMBER THAMES DOVER WIGHT PORTLAND: NORTH BACKING WEST OR NORTHWEST, 5 TO 7,
DECREASING 4 OR 5, OCCASIONALLY 6 LATER IN HUMBER AND THAMES. MODERATE OR
ROUGH. RAIN THEN FAIR. GOOD.

Reply | Threaded
Open this post in threaded view
|

Re: what to make of this fellow named __ipairs?

Alexander Gladysh
On Fri, Jan 28, 2011 at 20:13, Tony Finch <[hidden email]> wrote:
> On Fri, 28 Jan 2011, Alexander Gladysh wrote:
>> On Fri, Jan 28, 2011 at 16:52, Tony Finch <[hidden email]> wrote:

>> > It may be worth allowing obj:[method](args)

>> I certainly miss this feature often. Is it hard to implement?

> Something like this:

<...>

Thank you, Tony. Can you please produce the same patch for LuaJIT 2?
(No, no need to, I'm kidding!)

Seriously, I should have asked "is it hard to be brought in into the language?".

Alexander.

Reply | Threaded
Open this post in threaded view
|

Re: what to make of this fellow named __ipairs?

Tony Finch
On Fri, 28 Jan 2011, Alexander Gladysh wrote:
>
> Thank you, Tony. Can you please produce the same patch for LuaJIT 2?

Something like this:

diff --git a/src/lj_parse.c b/src/lj_parse.c
index b9338c2..2c22a22 100644
--- a/src/lj_parse.c
+++ b/src/lj_parse.c
@@ -601,9 +601,12 @@ static void bcemit_method(FuncState *fs, ExpDesc *e,
ExpDesc *key)
   expr_free(fs, e);
   func = fs->freereg;
   bcemit_AD(fs, BC_MOV, func+1, obj);  /* Copy object to first argument. */
-  lua_assert(expr_isstrk(key));
-  idx = const_str(fs, key);
-  if (idx <= BCMAX_C) {
+  if (!expr_isstrk(key)) {
+    bcreg_reserve(fs, 3);
+    expr_toreg(fs, key, func+2);
+    bcemit_ABC(fs, BC_TGETV, func, obj, func+2);
+    fs->freereg--;
+  } else if ((idx = const_str(fs, key)) < BCMAX_C) {
     bcreg_reserve(fs, 2);
     bcemit_ABC(fs, BC_TGETS, func, obj, idx);
   } else {
@@ -1614,7 +1617,11 @@ static void expr_primary(LexState *ls, ExpDesc *v)
     } else if (ls->token == ':') {
       ExpDesc key;
       lj_lex_next(ls);
-      expr_str(ls, &key);
+      expr_toanyreg(fs, v);
+      if (ls->token == '[')
+        expr_bracket(ls, &key);
+      else
+        expr_str(ls, &key);
       bcemit_method(fs, v, &key);
       parse_args(ls, v);
     } else if (ls->token == '(' || ls->token == TK_string ||


Tony.
--
f.anthony.n.finch  <[hidden email]>  http://dotat.at/
HUMBER THAMES DOVER WIGHT PORTLAND: NORTH BACKING WEST OR NORTHWEST, 5 TO 7,
DECREASING 4 OR 5, OCCASIONALLY 6 LATER IN HUMBER AND THAMES. MODERATE OR
ROUGH. RAIN THEN FAIR. GOOD.

Reply | Threaded
Open this post in threaded view
|

Re: what to make of this fellow named __ipairs?

Rena
In reply to this post by Tony Finch
On Fri, Jan 28, 2011 at 06:52, Tony Finch <[hidden email]> wrote:

> On Fri, 28 Jan 2011, joao lobato wrote:
>>
>> What about the case when wants to discover the method name at runtime:
>
> It may be worth allowing obj:[method](args)
>
>> I guess I got a bit philosophical, my point is that, in my opinion, if
>> one mixes container data with methods, it looks like bad design.
>
> Yes. I would like it to be easier and more efficient to do that.
>
> Tony.
> --
> f.anthony.n.finch  <[hidden email]>  http://dotat.at/
> HUMBER THAMES DOVER WIGHT PORTLAND: NORTH BACKING WEST OR NORTHWEST, 5 TO 7,
> DECREASING 4 OR 5, OCCASIONALLY 6 LATER IN HUMBER AND THAMES. MODERATE OR
> ROUGH. RAIN THEN FAIR. GOOD.
>
>

I've often wondered why I can do:
foo.bar:baz(4) --> foo.bar.baz(foo.bar, 4)
but not:
foo:bar.baz(4) --> foo.bar.baz(foo, 4)
or perhaps even:
foo:bar:baz(4) --> foo.bar.baz(foo, foo.bar, 4)
(although to be honest I can't think of a lot of uses for that last
one; just a random thought.)

--
Sent from my toaster.

Reply | Threaded
Open this post in threaded view
|

Re: what to make of this fellow named __ipairs?

Xavier Wang
In reply to this post by Tony Finch


2011/1/29 Tony Finch <[hidden email]>
On Fri, 28 Jan 2011, Alexander Gladysh wrote:
> On Fri, Jan 28, 2011 at 16:52, Tony Finch <[hidden email]> wrote:
>
> > It may be worth allowing obj:[method](args)
>
> I certainly miss this feature often. Is it hard to implement?

Something like this:

diff --git a/src/lcode.c b/src/lcode.c
index 6194749..adbe971 100644
--- a/src/lcode.c
+++ b/src/lcode.c
@@ -500,12 +500,17 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
 }


-void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
+int luaK_self1 (FuncState *fs, expdesc *e) {
  int func;
  luaK_exp2anyreg(fs, e);
  freeexp(fs, e);
  func = fs->freereg;
  luaK_reserveregs(fs, 2);
+  return func;
+}
+
+
+void luaK_self2 (FuncState *fs, int func, expdesc *e, expdesc *key) {
  luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key));
  freeexp(fs, key);
  e->u.s.info = func;
diff --git a/src/lcode.h b/src/lcode.h
index b941c60..4aaeb01 100644
--- a/src/lcode.h
+++ b/src/lcode.h
@@ -55,7 +55,8 @@ LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
 LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
 LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
 LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e);
-LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
+LUAI_FUNC int luaK_self1 (FuncState *fs, expdesc *e);
+LUAI_FUNC void luaK_self2 (FuncState *fs, int func, expdesc *e, expdesc *key);
 LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
 LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
 LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
diff --git a/src/lparser.c b/src/lparser.c
index 7ff0925..c684a78 100644
--- a/src/lparser.c
+++ b/src/lparser.c
@@ -778,10 +778,15 @@ static void primaryexp (LexState *ls, expdesc *v) {
        break;
      }
      case ':': {  /* `:' NAME funcargs */
+        int func;
        expdesc key;
        luaX_next(ls);
-        checkname(ls, &key);
-        luaK_self(fs, v, &key);
+        func = luaK_self1(fs, v);
+        if (ls->t.token == '[')
+          yindex(ls, &key);
+        else
+          checkname(ls, &key);
+        luaK_self2(fs, func, v, &key);
        funcargs(ls, v);
        break;
      }


Tony.
--
f.anthony.n.finch  <[hidden email]>  http://dotat.at/
HUMBER THAMES DOVER WIGHT PORTLAND: NORTH BACKING WEST OR NORTHWEST, 5 TO 7,
DECREASING 4 OR 5, OCCASIONALLY 6 LATER IN HUMBER AND THAMES. MODERATE OR
ROUGH. RAIN THEN FAIR. GOOD.

Is it possible merge into official lua sources?