Has Lua reached perfection?

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

Re: Has Lua reached perfection?

nobody
On 2018-01-28 13:09, Tony Papadimitriou wrote:
> The only thing I would certainly add to Lua is a `yield` keyword to
> complement `return` similar to Python’s way.

You sure that's a good idea?

How would you prevent code from using coroutines?  Right now, you just
take away the `coroutine` library (e. g. in a sandboxed _ENV) and you
know that the code won't (be able to) use it.

How would you 'tag' results coming from certain coroutines?  (E.g. all
workers always `yield( "worker", id, ret... )`.)  Right now, you write a
wrapper function and call that instead.  If yield is a keyword, I hope
you're not manually hard-coding the prefix everywhere but will also use
a wrapper, right?

So, what has been gained? (...and what has been lost?)

(This is another instance of the saddle-not-optima thing I was referring
to in another branch of this thread.)

-- nobody

Reply | Threaded
Open this post in threaded view
|

Re: Has Lua reached perfection?

Soni "They/Them" L.


On 2018-01-29 12:01 AM, nobody wrote:

> On 2018-01-28 13:09, Tony Papadimitriou wrote:
>> The only thing I would certainly add to Lua is a `yield` keyword to
>> complement `return` similar to Python’s way.
>
> You sure that's a good idea?
>
> How would you prevent code from using coroutines?  Right now, you just
> take away the `coroutine` library (e. g. in a sandboxed _ENV) and you
> know that the code won't (be able to) use it.
>
> How would you 'tag' results coming from certain coroutines?  (E.g. all
> workers always `yield( "worker", id, ret... )`.)  Right now, you write a
> wrapper function and call that instead.  If yield is a keyword, I hope
> you're not manually hard-coding the prefix everywhere but will also use
> a wrapper, right?
>
> So, what has been gained? (...and what has been lost?)
>
> (This is another instance of the saddle-not-optima thing I was referring
> to in another branch of this thread.)
>

I guess if it's just sugar...

> -- nobody
>

--
Disclaimer: these emails may be made public at any given time, with or without reason. If you don't agree with this, DO NOT REPLY.


Reply | Threaded
Open this post in threaded view
|

Re: Has Lua reached perfection?

Sean Conner
In reply to this post by nobody
It was thus said that the Great nobody once stated:
> Beside incoming improvements, present Lua also contains lots of tiny
> warts... NaN being unusable as a table key is one of the bigger kinks –
> a "discontinuity" in the type/value space that's hard to check for and
> generates complexity whenever you have to deal with it.

  Just in case you are unaware (or others are unaware), NaN is a special
value defined by IEEE-754 (or rather, values) that have a unique property:

        x = 0/0
        print(x,x==x)
        nan false

A NaN is not equal to anything, including itself!  In fact, according to the
standard, this:

        x = 0/0
        y = 0/0

is not even guarenteed to produce the same bit pattern!  x and y just have
to be designated as NaN.  So it would be difficult to make NaN to be a table
value.  

  -spc

Reply | Threaded
Open this post in threaded view
|

Re: Has Lua reached perfection?

Sean Conner
It was thus said that the Great Sean Conner once stated:

> It was thus said that the Great nobody once stated:
> > Beside incoming improvements, present Lua also contains lots of tiny
> > warts... NaN being unusable as a table key is one of the bigger kinks –
> > a "discontinuity" in the type/value space that's hard to check for and
> > generates complexity whenever you have to deal with it.
>
>   Just in case you are unaware (or others are unaware), NaN is a special
> value defined by IEEE-754 (or rather, values) that have a unique property:
>
> x = 0/0
> print(x,x==x)
> nan false
>
> A NaN is not equal to anything, including itself!  In fact, according to the
> standard, this:
>
> x = 0/0
> y = 0/0
>
> is not even guarenteed to produce the same bit pattern!  x and y just have
> to be designated as NaN.  So it would be difficult to make NaN to be a table
> value.  

  I meant to say "it would be difficult to make NaN to be a table key."

  -spc (Sigh)


Reply | Threaded
Open this post in threaded view
|

Re: NaN as table key [w/ patch for 5.3.3] (was: Has Lua reached perfection?)

nobody
In reply to this post by Sean Conner
On 2018-01-29 03:16, Sean Conner wrote:
> It was thus said that the Great nobody once stated:
>> NaN being unusable as a table key is one of the bigger kinks
>
> Just in case you are unaware (or others are unaware), NaN is a
> special value defined by IEEE-754 (or rather, values) that have a
> unique property:
>

I referred to that in the footnote down below...

>> [2] [...] have special case logic for the float paths in the table
>> code, possibly substituting a single "canonical" NaN (recall that
>> there's billions of them... =/) for use as a key.  Last time I
>> patched this [...] I was able to hide most of the code on error
>> paths / behind checks that already existed.

...and because you say...

> So it would be difficult to make NaN to be a table [key].

...and it wasn't actually that hard, here's the patch with my notes from
back then.  The code is still rather ugly / proof-of-concept / just make
it work somehow-style and can almost certainly be improved, I just don't
have the time to do that right now.

I think I had some tests somewhere and ran them, the code passed some
Lua test suite back then (mod obvious/expected breakage?), and I
definitely used it (until 5.3.4 it was always-on in my default Lua
interpreter and I never noticed any problems, now I'd have to find the
time to update this...) - but I don't have a deep understanding of the
table code so I'm not sure this is correct and so it's probably better
to treat this as untested experimental code and check for yourself if it
does what you expect it to do.

It applies to something like 5.3.1--5.3.3 IIRC, and I think (but didn't
check right now) that it was 5.3.4 that changed some table code.

To what's below, let me add this:

  *  It's ~40 lines, which is _a lot_ for such a pesky little detail.
     (Floats are ugly...)  But if you actually have to deal with NaN,
     those 40 lines are a lot less than what you need to make things
     work in Lua somehow.  (And if you actually (have to) do the checks,
     doing them in C is faster too.)

  *  Code doesn't do the canonical NaN thing yet, so if you put in -NaN
     and then ask for NaN, you'll get the -NaN value. (Sign is irrelevant
     as for +0.0 / -0.0, but for 0 it's hidden by the cast to int while
     for NaN you can see the wrong sign.  Always Using a canonical NaN
     would make it behave as for -0.0 --> 0.)

-- nobody

(Patch is public domain or fallback CC-0, yadda yadda.)

-----

Quite a bit of code needed (+36,-2,~1), all but one check off the main
path.

`searchnan` handles the NaN-finding logic, used by `findnan`/`getnan`.

The three cases to handle are:

  * Traversal (next, pairs), done by `findindex`.  Previously, NaN would
    have hit the `luaG_runerror("invalid key to 'next'")` branch.
    As this should be pretty rare, we check for NaN in here and possibly
    defer to `findnan`.  It just calls `searchnan` and extracts the
    offset from the resulting `Node*` (or `luaG_runerror`s if there's no
    NaN in the table.)

  * Finding (possibly for subsequent update of) an entry, done by
    `luaH_get`.  Previously, `getgeneric` would have done the (futile)
    search for NaN, never finding it.
    This needs an extra branch in `luaH_get` in the `LUA_TNUMFLT` case,
    which could be costly.  If the key is NaN, we branch to `getnan`,
    which returns the node's key or `luaO_nilobject`.

  * Adding a new node, done by `luaH_newkey`.  Previously, this did an
    explicit check for NaN and would have errored out.
    As the rest of the code now handles NaN, this check is no longer
    needed, for a slight speedup of all insertions of float keys.

Assuming code rarely uses `next` with nonexistent keys, the impact of #1
should be negligible.  #3 is a slight speedup for insertion, #2 an equal
slowdown for lookups.  Depending on the ratio of insertions to lookups,
this could come out anywhere between neutral and significant slowdown.

`searchnan` can probably still be improved.  It currently returns `NULL`
if no NaN-node exists, which is a nonstandard pattern in the code base.
It currently takes the key as argument only to find the main position.
As the key cannot be used for comparison, this could be removed if the
main position of NaN can be gotten in other ways.  (The default
`l_hashfloat` always assigns 0, but it can be re`#define`d so that's not
generally a safe assumption.)

---
  src/ltable.c | 40 +++++++++++++++++++++++++++++++++++++---
  1 file changed, 37 insertions(+), 3 deletions(-)

diff --git a/src/ltable.c b/src/ltable.c
index 7e15b71..9e5deba 100644
--- a/src/ltable.c
+++ b/src/ltable.c
@@ -152,6 +152,31 @@ static unsigned int arrayindex (const TValue *key) {
    return 0;  /* 'key' did not match some condition */
  }

+static const Node *searchnan (const Table *t, const TValue *key) {
+  Node *n;
+  int nx;
+  lua_assert(ttisfloat(key) && luai_numisnan(fltvalue(key)));
+  n = mainposition(t, key);
+  for (;;) {
+    if (ttisfloat(gkey(n)) && luai_numisnan(fltvalue(gkey(n))))
+      return n;
+    else {
+      nx = gnext(n);
+      if (nx == 0)
+        return NULL;
+      n += nx;
+    }
+  }
+}
+
+static unsigned int findnan(lua_State *L, Table *t, StkId key) {
+  unsigned int i;
+  const Node *n = searchnan(t, key);
+  if (n == NULL)
+    luaG_runerror(L, "invalid key to 'next'");
+  i = cast_int(n - gnode(t, 0));
+  return (i+1) + t->sizearray;
+}

  /*
  ** returns the index of a 'key' for table traversals. First goes all
@@ -177,8 +202,11 @@ static unsigned int findindex (lua_State *L, Table
*t, StkId key) {
          return (i + 1) + t->sizearray;
        }
        nx = gnext(n);
-      if (nx == 0)
+      if (nx == 0) {
+        if (ttisfloat(key) && luai_numisnan(fltvalue(key))) /* it's NaN! */
+          return findnan(L, t, key);
          luaG_runerror(L, "invalid key to 'next'");  /* key not found */
+      }
        else n += nx;
      }
    }
@@ -449,8 +477,6 @@ TValue *luaH_newkey (lua_State *L, Table *t, const
TValue *key) {
        setivalue(&aux, k);
        key = &aux;  /* insert it as an integer */
      }
-    else if (luai_numisnan(fltvalue(key)))
-      luaG_runerror(L, "table index is NaN");
    }
    mp = mainposition(t, key);
    if (!ttisnil(gval(mp)) || isdummy(mp)) {  /* main position is taken? */
@@ -533,6 +559,12 @@ const TValue *luaH_getshortstr (Table *t, TString
*key) {
    }
  }

+static const TValue *getnan (Table *t, const TValue *key) {
+  const Node *n = searchnan(t, key);
+  if (n == NULL)
+    return luaO_nilobject;
+  return gval(n);
+}

  /*
  ** "Generic" get version. (Not that generic: not valid for integers,
@@ -576,6 +608,8 @@ const TValue *luaH_get (Table *t, const TValue *key) {
        lua_Integer k;
        if (luaV_tointeger(key, &k, 0)) /* index is int? */
          return luaH_getint(t, k);  /* use specialized version */
+      else if (luai_numisnan(fltvalue(key)))
+        return getnan(t, key);
        /* else... */
      }  /* FALLTHROUGH */
      default:

Reply | Threaded
Open this post in threaded view
|

Re: Has Lua reached perfection?

Italo Maia
In reply to this post by Sean Conner
I don't think lua, as a language, is perfect either, but it is in the right track. After seeing https://www.youtube.com/watch?v=EUvgoxBm7uc from Roberto, the way lua walks forwards becomes much clearer. 
Anyhow, coming from python, I hardly miss a switch/case structure but, an yield would be certainly interesting to gave upon. Also, type annotation would be very nice (helloooo ravi). Large code-bases could benefit tremendously from it.
Regarding OO with Lua, I hardly miss a built-in "class" support, but the lack of a standard interface for OO Lua libraries is a big bummer. Lots of incompatible OO libs. Something like: "if you want to build a lib to do this, try to make it compatible with this interface/behavior".


2018-01-28 23:20 GMT-03:00 Sean Conner <[hidden email]>:
It was thus said that the Great Sean Conner once stated:
> It was thus said that the Great nobody once stated:
> > Beside incoming improvements, present Lua also contains lots of tiny
> > warts... NaN being unusable as a table key is one of the bigger kinks –
> > a "discontinuity" in the type/value space that's hard to check for and
> > generates complexity whenever you have to deal with it.
>
>   Just in case you are unaware (or others are unaware), NaN is a special
> value defined by IEEE-754 (or rather, values) that have a unique property:
>
>       x = 0/0
>       print(x,x==x)
>       nan     false
>
> A NaN is not equal to anything, including itself!  In fact, according to the
> standard, this:
>
>       x = 0/0
>       y = 0/0
>
> is not even guarenteed to produce the same bit pattern!  x and y just have
> to be designated as NaN.  So it would be difficult to make NaN to be a table
> value.

  I meant to say "it would be difficult to make NaN to be a table key."

  -spc (Sigh)





--
"A arrogância é a arma dos fracos."

===========================
Me. Italo Moreira Campelo Maia
Co-fundador do Grupo de Usuários Python do Ceará
Secretário ForHacker (fb.com/ForHackerSpace)
Desenvolvedor Full-Stack, Escritor, Empresário, Visionário
-----------------------------------------------------
Meu Livro, Site, Blog
===========================
Reply | Threaded
Open this post in threaded view
|

Re: Has Lua reached perfection?

Italo Maia
ps: Sorry; Class-Commons does just that.

2018-01-29 1:40 GMT-03:00 Italo Maia <[hidden email]>:
I don't think lua, as a language, is perfect either, but it is in the right track. After seeing https://www.youtube.com/watch?v=EUvgoxBm7uc from Roberto, the way lua walks forwards becomes much clearer. 
Anyhow, coming from python, I hardly miss a switch/case structure but, an yield would be certainly interesting to gave upon. Also, type annotation would be very nice (helloooo ravi). Large code-bases could benefit tremendously from it.
Regarding OO with Lua, I hardly miss a built-in "class" support, but the lack of a standard interface for OO Lua libraries is a big bummer. Lots of incompatible OO libs. Something like: "if you want to build a lib to do this, try to make it compatible with this interface/behavior".


2018-01-28 23:20 GMT-03:00 Sean Conner <[hidden email]>:
It was thus said that the Great Sean Conner once stated:
> It was thus said that the Great nobody once stated:
> > Beside incoming improvements, present Lua also contains lots of tiny
> > warts... NaN being unusable as a table key is one of the bigger kinks –
> > a "discontinuity" in the type/value space that's hard to check for and
> > generates complexity whenever you have to deal with it.
>
>   Just in case you are unaware (or others are unaware), NaN is a special
> value defined by IEEE-754 (or rather, values) that have a unique property:
>
>       x = 0/0
>       print(x,x==x)
>       nan     false
>
> A NaN is not equal to anything, including itself!  In fact, according to the
> standard, this:
>
>       x = 0/0
>       y = 0/0
>
> is not even guarenteed to produce the same bit pattern!  x and y just have
> to be designated as NaN.  So it would be difficult to make NaN to be a table
> value.

  I meant to say "it would be difficult to make NaN to be a table key."

  -spc (Sigh)





--
"A arrogância é a arma dos fracos."

===========================
Me. Italo Moreira Campelo Maia
Co-fundador do Grupo de Usuários Python do Ceará
Secretário ForHacker (fb.com/ForHackerSpace)
Desenvolvedor Full-Stack, Escritor, Empresário, Visionário
-----------------------------------------------------
Meu Livro, Site, Blog
===========================



--
"A arrogância é a arma dos fracos."

===========================
Me. Italo Moreira Campelo Maia
Co-fundador do Grupo de Usuários Python do Ceará
Secretário ForHacker (fb.com/ForHackerSpace)
Desenvolvedor Full-Stack, Escritor, Empresário, Visionário
-----------------------------------------------------
Meu Livro, Site, Blog
===========================
Reply | Threaded
Open this post in threaded view
|

Re: Has Lua reached perfection?

Paige DePol
In reply to this post by Italo Maia
Italo Maia <[hidden email]> wrote:

> I don't think lua, as a language, is perfect either, but it is in the
> right track. After seeing https://www.youtube.com/watch?v=EUvgoxBm7uc from
> Roberto, the way lua walks forwards becomes much clearer. Anyhow, coming
> from python, I hardly miss a switch/case structure but, an yield would be
> certainly interesting to gave upon. Also, type annotation would be very
> nice (helloooo ravi). Large code-bases could benefit tremendously from it.
> Regarding OO with Lua, I hardly miss a built-in "class" support, but the
> lack of a standard interface for OO Lua libraries is a big bummer. Lots of
> incompatible OO libs. Something like: "if you want to build a lib to do
> this, try to make it compatible with this interface/behavior".

I like type annotation as well as a defined OO model, both of which I have
also implemented. Interestingly, from what I have seen the Ravi author and I
implemented types nearly the same way, though we did choose differing syntax
for the language.

A built-in class model does allow for some very nice optimisations of the
encapsulated data. If the compiler knows the data you are using, and you
make that data easy and fast to access, then the OO model should be much
more performant vs the metatable method of implementing classes.

I really do like the minimalist approach to Lua... I just think my idea
of minimal is a bit more than that of Team Lua. However, that is not a
bad thing as it means there is a very nice solid base to build upon!

I still need to learn more about co-routines, I get what they are but I
don't think the entire concept of when and how to use them has clicked
quite yet. That said, I would love to see if it would be possible to
implement a version of libdispatch (Grand Central Dispatch in macOS)
to Lua along with creating "blocks" of code... which are really just
closures with slightly different upvalue scope rules if I recall.

~Paige


Reply | Threaded
Open this post in threaded view
|

Re: Has Lua reached perfection?

Sean Conner
It was thus said that the Great Paige DePol once stated:
>
> I still need to learn more about co-routines, I get what they are but I
> don't think the entire concept of when and how to use them has clicked
> quite yet.

  A good example would be event programming for a network based server.
Each "connection" or "request" can be handled by a co-routine.  The examples
I have are rather large, but generally, they look like (very pseudocodeish
here, even for Lua):

        function handler(remote,data)
          do_something_that_doesnt_block(data)
          remote,data = coroutine.yield(remote,data)
          do_something_else(remote,data)
          runnable[remote] = nil
        end

        function mainloop(socket)
          data,raddr = socket:read()

          if newrequest(data) then
            co = coroutine.create(handler)
            runnable[raddr] = co
          else
            coroutine.resume(runnable[raddr],raddr,data)
          end
          return mainloop(socket)
        end

At least, that's how the code I've written has been generally structured
(although more verbose).  

> That said, I would love to see if it would be possible to
> implement a version of libdispatch (Grand Central Dispatch in macOS)
> to Lua along with creating "blocks" of code... which are really just
> closures with slightly different upvalue scope rules if I recall.

  I don't see why not.  

  -spc (And I don't even know what Grand Central Dispatch is)

Reply | Threaded
Open this post in threaded view
|

Re: Has Lua reached perfection?

Dirk Laurie-2
In reply to this post by Italo Maia
2018-01-29 6:41 GMT+02:00 Italo Maia <[hidden email]>:
> 2018-01-29 1:40 GMT-03:00 Italo Maia <[hidden email]>:
>> Regarding OO with Lua, I hardly miss a built-in "class" support, but the
>> lack of a standard interface for OO Lua libraries is a big bummer. Lots of
>> incompatible OO libs. Something like: "if you want to build a lib to do
>> this, try to make it compatible with this interface/behavior".

> ps: Sorry; [Class-Commons](https://github.com/bartbes/Class-Commons) does just that.

There are also attempts to standardize in several rocks, e.g. Penlight.
Needless to say, they are incompatible with Class-Commons.

Taken together, these make a perfect illustration of why
a standard for Lua OO will never fly. There are so many
ways, and no one is best.

Moreover, it is so easy to roll one's own. The simplest kind takes
maybe 15-20 lines, see below. I just include it in every project
where it is needed and make it global. With something so short
and there to be read, why must I require an external module
and ask the reader to go and read its documentation?

It is based on the notion of a constructor-metatable.

Usage:
   MyClass = class("My Class",methods)  -- optional 'methods': a table
to be inherited
   object = MyClass(...)  -- constructs an empty object, calls
object:init() if it exists.

The code is probably somewhere in PiL, but anyway, here it is.
Works for >=5.1, but  __name is only useful >=5.3. For 5.0, remove
the vararg.

         do  -- encapsulate 'new' as upvalue to 'class'
local new = function(Class,...)  -- generic constructor for all classes
  object = setmetatable({},Class)
  if type(Class.init)=='function' then object:init(...) end
  return object
end

class = function(name,_methods)   -- class creator
  local meta = { __call=new,
    __name="constructor-metatable for class '"..name.."'";
    __index = _methods
    }
  local methods = {__name = name}
  methods.__index = methods
  return setmetatable(methods,meta)
end
         end -- of class mechanism

Reply | Threaded
Open this post in threaded view
|

Re: NaN as table key [w/ patch for 5.3.3] (was: Has Lua reached perfection?)

Dirk Laurie-2
In reply to this post by nobody
2018-01-29 5:31 GMT+02:00 nobody <[hidden email]>:

> On 2018-01-29 03:16, Sean Conner wrote:
>>
>> It was thus said that the Great nobody once stated:
>>>
>>> NaN being unusable as a table key is one of the bigger kinks
>>
>>
>> Just in case you are unaware (or others are unaware), NaN is a special
>> value defined by IEEE-754 (or rather, values) that have a unique property:
>>
>> So it would be difficult to make NaN to be a table [key].
>
>
> ...and it wasn't actually that hard, here's the patch with my notes from
> back then.  The code is still rather ugly / proof-of-concept / just make
> it work somehow-style and can almost certainly be improved, I just don't
> have the time to do that right now.

Why must every little feature that is perfectly easy in Lua
be a patch or a new feature? Why can't one just do this:

do  local NaN = setmetatable({},{__tostring=function() return "NaN" end})
tbl = setmetatable({},{
  __index = function(tbl,idx) if idx~=idx then return rawget(tbl,"NaN") end end;
  __newindex = function(tbl,idx,val) if idx~=idx then
rawset(tbl,"NaN",val) end end;
})
end

> tbl[0/0] = "not a number"
> tbl[0/0]
not a number
> next(tbl)
NaN    not a number

Reply | Threaded
Open this post in threaded view
|

Re: Has Lua reached perfection?

Soni "They/Them" L.
In reply to this post by Dirk Laurie-2


On 2018-01-29 07:02 AM, Dirk Laurie wrote:

> 2018-01-29 6:41 GMT+02:00 Italo Maia <[hidden email]>:
>> 2018-01-29 1:40 GMT-03:00 Italo Maia <[hidden email]>:
>>> Regarding OO with Lua, I hardly miss a built-in "class" support, but the
>>> lack of a standard interface for OO Lua libraries is a big bummer. Lots of
>>> incompatible OO libs. Something like: "if you want to build a lib to do
>>> this, try to make it compatible with this interface/behavior".
>> ps: Sorry; [Class-Commons](https://github.com/bartbes/Class-Commons) does just that.
> There are also attempts to standardize in several rocks, e.g. Penlight.
> Needless to say, they are incompatible with Class-Commons.
>
> Taken together, these make a perfect illustration of why
> a standard for Lua OO will never fly. There are so many
> ways, and no one is best.
>
> Moreover, it is so easy to roll one's own. The simplest kind takes
> maybe 15-20 lines, see below. I just include it in every project
> where it is needed and make it global. With something so short
> and there to be read, why must I require an external module
> and ask the reader to go and read its documentation?
>
> It is based on the notion of a constructor-metatable.
>
> Usage:
>     MyClass = class("My Class",methods)  -- optional 'methods': a table
> to be inherited
>     object = MyClass(...)  -- constructs an empty object, calls
> object:init() if it exists.
>
> The code is probably somewhere in PiL, but anyway, here it is.
> Works for >=5.1, but  __name is only useful >=5.3. For 5.0, remove
> the vararg.
>
>           do  -- encapsulate 'new' as upvalue to 'class'
> local new = function(Class,...)  -- generic constructor for all classes
>    object = setmetatable({},Class)
>    if type(Class.init)=='function' then object:init(...) end
>    return object
> end
>
> class = function(name,_methods)   -- class creator
>    local meta = { __call=new,
>      __name="constructor-metatable for class '"..name.."'";
>      __index = _methods
>      }
>    local methods = {__name = name}
>    methods.__index = methods
>    return setmetatable(methods,meta)
> end
>           end -- of class mechanism
>

Ah, OOP you say? Here's the simplest form of OOP:
https://bitbucket.org/TeamSoni/cratera

Features:
- No inheritance
- Written in C
- Combine traits from multiple sources (similar to multiple inheritance,
but without the drawbacks)
- Compatible with standard Lua

--
Disclaimer: these emails may be made public at any given time, with or without reason. If you don't agree with this, DO NOT REPLY.


Reply | Threaded
Open this post in threaded view
|

Re: Has Lua reached perfection?

Francisco Olarte
In reply to this post by Tony Papadimitriou
Tony:

On Sun, Jan 28, 2018 at 7:34 PM, Tony Papadimitriou <[hidden email]> wrote:
...
>>> The current method (or hack) of implementing co-routines is unnecessarily
>>> verbose and often resulting in hard to understand code.
>> How do you think this will improve?
> Re-read the sentence just above your question to see how.

Did it before, and thought the only proposal was changing
cortoutine.yield by yield, which can already be done with a local.

Or, if changing to be the python way, mutilating it to have generators.


>> In Lua? Coroutines are what they have been in nearly every other
>> system I've used, same functions as packages I've used in C, C++,
>> Pascal and even assembler ( 8 bit one ). Nothing especial to be done
>> in any function used in a coroutine heavy program, just a couple
>> function calls.
> An what more 'special' is done with Python's `yield`?  You just
> replace `return` with `yield` and you turn any function into a
> co-routine.  Can't get much simpler.

No. You turn a function into a generator. A generator is not a
coroutine, as you are very restricted in what you can do with it.

It's been a time since I used it, as generators where not able to do
what I wanted. And TFM (
https://docs.python.org/3/reference/expressions.html#yieldexpr )
states "The yield expression is used when defining a generator
function or an asynchronous generator function and thus can only be
used in the body of a function definition. Using a yield expression in
a function’s body causes that function to be a generator, and using it
in an async def function’s body causes that coroutine function to be
an asynchronous generator.", and a little later "All of this makes
generator functions quite similar to coroutines; they yield multiple
times, they have more than one entry point and their execution can be
suspended. The only difference is that a generator function cannot
control where the execution should continue after it yields; the
control is always transferred to the generator’s caller.". This only
difference is subtle, but very important when using coroutines for
serious work.


Try to take an event loop and move it to coroutine processing, with
the simple "yield" it's a nightmare, that's why they are trying to put
all the "async" stuff in place. With "yield" you have to write all the
code in a single function, not with coroutines. Of course you can add
things like async def / async for, await , but then you are no longer
simple.


> I didn't talk about changing how co-routines are implemented internally,
> (and, as a user, it's none of my business), just how one has to implement
> them in their own Lua code.  Call it 'syntactic sugar' if you like.
> Same as having `a = function() end` be (almost) equivalent to
> `function a() end`

The thing is in lua a coroutine can run any function. You could add
syntactic sugar like...

>
> In other words, I prefer this:
>
> function xxx(n)
>  for i = 1, n do yield i*i end
> end
>
> to this:
>
> function xxx(n)
>  return coroutine.wrap(function() for i = 1, n do coroutine.yield(i*i) end end)
> end


That is an example of basically a very simple generator. Of course
python syntax is better for this, it is what it was dessigned for.

But the problem is, if you make it functionally equivalent to the
second variant, it is not a particularly useful lua idiom, as lua
loops work differently than python ones, in lua you would not even use
a coroutine for that. How are you going to use it, define a function
which returns 1, xxx(n) and coroutine.resume, or sme variant of it, to
be able to use them in a loop?

> Now, if the latter is more appealing to you, good for you.
> "In matters of taste, there can be no disputes."

No dispute, just trying to see your point. Now I think you want
generators, not coroutines, so you prefer generator syntax.

Now try something like the stuff I do in one of my programs. I'm doing
an IVR. When a call comes in I build an object and call it's main
method in a coroutine. The main method eventually calls one "wait for
whatever" method deep in the library, which yields some context info
which I store, and then the IVR creator exits. Then an event, say a
dtmf, comes. From the handler I locate the ivr object based on the
call and resume it, wait method deep in the library returns and IVR
continues. This is not so easy to do if every function in the library
containing a yield is magically turned into a coroutine. In python
they even need yield from to be able to do that, IIRC, another
keyword.

Those kind of things need real coroutines, not generators.


Francisco Olarte.

Reply | Threaded
Open this post in threaded view
|

Re: Has Lua reached perfection?

kurapica
In reply to this post by Dibyendu Majumdar

-----Original Message-----
From: Tony Papadimitriou

>In other words, I prefer this:

>function xxx(n)
>  for i = 1, n do yield i*i end
>end
>
>to this:
>
>function xxx(n)
>  return coroutine.wrap(function() for i = 1, n do coroutine.yield(i*i) end
>end)
>end

>Now, if the latter is more appealing to you, good for you.
>"In matters of taste, there can be no disputes."

>>Francisco Olarte.

>Tony P.

 

I have an oop lib of pure Lua, it use the objects as environment, and with a special attribute system(like the decorator in Python, but a little complex) can provide such “syntax sugar” like

 

    require "PLoop"

 

    _ENV = Module "Test" "v1.0"  -- Create a module object as environment

 

    import "System.Threading"

 

    __Iterator__()   -- Wrap the next function as iterator runs as coroutine

    function iter(i, j, step)

        for k = i, j, step or 1 do

            coroutine.yield(k, k^2)

        end

    end

 

-- Use it like pairs, the coroutine is generated by a pool

-- and will be recycled automatically

    for k, v in iter (1, 10, 1) do

        print(k, v)

    end

The trick is very simple, the environment is controlled by the module object, so it know when a new function is defined and registered attribute can be used on it, no doubt you can create your own version.

123