Assignment Expressions in Lua

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

Assignment Expressions in Lua

Pedro Tammela-2
In Python 3.8 there will be a new feature introducing Assignment Expressions[1]. One of the reasons for such feature is to improve code readability, among other things.

Would assignment expressions improve Lua code readability?

Reply | Threaded
Open this post in threaded view
|

Re: Assignment Expressions in Lua

Coda Highland
On Tue, Jul 23, 2019 at 9:10 AM Pedro Tammela <[hidden email]> wrote:
In Python 3.8 there will be a new feature introducing Assignment Expressions[1]. One of the reasons for such feature is to improve code readability, among other things.

Would assignment expressions improve Lua code readability?


Python programmers want assignment expressions because Python's comprehension syntax is so heavily used. They've been asking for assignment expressions literally for decades and it's only now that Python's programming style has evolved to the point where it's hard to express some things in any other efficient way that Guido has given in to the pressure.

But Python's programming style has only evolved that way BECAUSE of Python's comprehension syntax. Lua does not have anything like it. Python's comprehension syntax involves evaluating an expression multiple times with different values, and nothing in Lua does this -- all expressions are evaluated immediately. If you want that behavior, you use a function, full stop.

Lua intentionally does not have assignment expressions; this was debated (again) fairly recently. Given that even PEP-572 includes explicit admonishments to avoid using assignment expressions except when absolutely necessary, and given that Python's rationale for including them doesn't apply to Lua, I see no reason why Lua's stance on the matter should change.

/s/ Adam
Reply | Threaded
Open this post in threaded view
|

Re: Assignment Expressions in Lua

Roberto Ierusalimschy
In reply to this post by Pedro Tammela-2
> In Python 3.8 there will be a new feature introducing Assignment
> Expressions[1]. One of the reasons for such feature is to improve code
> readability, among other things.

That feature was also the main reason for Guido stepping down as
Python's BDFL :-)

(Ok, not the feature itself, but the discussions around it.)

-- Roberto

Reply | Threaded
Open this post in threaded view
|

Re: Assignment Expressions in Lua

nobody
In reply to this post by Pedro Tammela-2
On 23/07/2019 16.10, Pedro Tammela wrote:
> In Python 3.8 there will be a new feature introducing Assignment
> Expressions[1]. One of the reasons for such feature is to improve
> code readability, among other things.
>
> Would assignment expressions improve Lua code readability?
>
> [1] https://www.python.org/dev/peps/pep-0572/

function Image.new( w, h )
   local self = { }
   for y = 1, h do
     local row = self[y] := { }
     for x = 1, w do
       row[x] = { 0, 0, 0 }
     end
   end
   return setmetatable( self, Image )
end

makes good use of := in

     local row = self[y] := { }

vs. what I usually do

     local row = { } ; self[y] = row

or (worse)

     local row = { }
     for … do
     end
     self[y] = row  -- easy to forget this line

Same for all sorts of other situations where you have to do multi-level
indexing.

I actually considered suggesting this on the list *before* it came up in
Python, but never actually bothered to because while it is slightly more
readable IMHO, there's just too many questions that would have to be
answered and I don't feel that's worth it.

(What about multiple-return expressions:  Can you assign only the first
value or all of them?  If only the first, do the return values truncate
to one result or do they still all go through?  Is this a pure
side-effect (assign x, result is x) or a store-read (assign x, read x
(which may have been changed by __newindex/__index))? Etc. etc. …)

-- nobody

v
Reply | Threaded
Open this post in threaded view
|

Re: Assignment Expressions in Lua

v
On Tue, 2019-07-23 at 16:59 +0200, nobody wrote:

> On 23/07/2019 16.10, Pedro Tammela wrote:
> > In Python 3.8 there will be a new feature introducing Assignment
> > Expressions[1]. One of the reasons for such feature is to improve
> > code readability, among other things.
> >
> > Would assignment expressions improve Lua code readability?
> >
> > [1] https://www.python.org/dev/peps/pep-0572/
>
> (What about multiple-return expressions:  Can you assign only the
> first
> value or all of them?  If only the first, do the return values
> truncate
> to one result or do they still all go through?  Is this a pure
> side-effect (assign x, result is x) or a store-read (assign x, read x
> (which may have been changed by __newindex/__index))? Etc. etc. …)
>
> -- nobody

I actually think that this isn't bad idea overall, but there's my point
of view onto this: assignment should pass its results after assigning
them (like it does in C/C++). Consider this:

a,g = self.data = local b = {},{}

This creates table, assigns it to local `b`, stores it into `self.data`
and assigns it to global `a`, without indexing `self` and *as well*
assigns different table to `b`.

This may come handy in other cases as well, but multireturn make it
uglier sometimes. For example:

local err,_ -- Define local _
if local val = _,err = returnValOrErr() then
...
end

is pretty ugly and it always will be when you need some complicated
multret.

However, I do approve this idea if it will allow to define variable
inside `if` condition.

--
v <[hidden email]>


Reply | Threaded
Open this post in threaded view
|

Re: Assignment Expressions in Lua

Viacheslav Usov
In reply to this post by Coda Highland
On Tue, Jul 23, 2019 at 4:36 PM Coda Highland <[hidden email]> wrote:

> Python programmers want assignment expressions because Python's comprehension syntax is so heavily used.

This is not a valid reason why a similar device cannot be beneficial in Lua.

Both examples shown in the rationale can be easily adapted to Lua and would be just as convincing.

So I would say the benefit of such a mechanism is not specific to Python and it is valid to consider it for Lua, too.

Just about any procedural language (Lua included) might force the user to write something like:

local x = func() -- expensive
if x > 0 then
  -- use x
end

The problem with the above is the pollution of an outer namespace, not to mention it is forced rather than natural. A bigger problem with that is the scope of the variable thus introduced with respect to its termination (to-be-closing) - instead of being that of the if-statement, it is the outer scope.

Ultimately, Lua has its own problem where one cannot write

local x = foo(), y = bar(x)

The correct version of that is more verbose and feels forced and unnatural. More so when it combines with the previous problem.

So while we are talking about all the weird and wonderful new semantics for Lua variables, it might be prudent to consider this, as well. Perhaps we could end up with something synthesizing multiple benefits, thus making it more likely to appear in Lua.
 
Cheers,
V.
Reply | Threaded
Open this post in threaded view
|

Re: Assignment Expressions in Lua

Coda Highland


On Tue, Jul 23, 2019 at 11:10 AM Viacheslav Usov <[hidden email]> wrote:
On Tue, Jul 23, 2019 at 4:36 PM Coda Highland <[hidden email]> wrote:

> Python programmers want assignment expressions because Python's comprehension syntax is so heavily used.

This is not a valid reason why a similar device cannot be beneficial in Lua.

Both examples shown in the rationale can be easily adapted to Lua and would be just as convincing.

So I would say the benefit of such a mechanism is not specific to Python and it is valid to consider it for Lua, too.

Just about any procedural language (Lua included) might force the user to write something like:

local x = func() -- expensive
if x > 0 then
  -- use x
end

The problem with the above is the pollution of an outer namespace, not to mention it is forced rather than natural. A bigger problem with that is the scope of the variable thus introduced with respect to its termination (to-be-closing) - instead of being that of the if-statement, it is the outer scope.

Ultimately, Lua has its own problem where one cannot write

local x = foo(), y = bar(x)

The correct version of that is more verbose and feels forced and unnatural. More so when it combines with the previous problem.

So while we are talking about all the weird and wonderful new semantics for Lua variables, it might be prudent to consider this, as well. Perhaps we could end up with something synthesizing multiple benefits, thus making it more likely to appear in Lua.
 
Cheers,
V.

Even the PEP in question says that this should be done with an assignment statement in the if/then example you provide. Assignments instead of comparisons inside of conditionals are one of the biggest reasons NOT to support assignment expressions. Python is working around the problem with it by introducing a new token to the grammar, but it's pretty explicitly stated in the PEP that comprehensions are a major part of the rationale. I presume that being able to use the lambda syntax to express assignments in callbacks is another. (And to be honest, I disagree with the rationale: comprehensions are a very functional-programming kind of thing, and assignments are by definition side-effect-bearing.) And Lua doesn't have comprehensions OR lambdas.

The other problem you cite I consider to be an additional reason NOT to do it. If making good use of something requires expanding the scope of the change, that's a big red flag, especially in a language whose design is as conservative as Lua's.

/s/ Adam
Reply | Threaded
Open this post in threaded view
|

Re: Assignment Expressions in Lua

Viacheslav Usov
On Tue, Jul 23, 2019 at 7:19 PM Coda Highland <[hidden email]> wrote:

> And Lua doesn't have comprehensions OR lambdas.

As stated already, Python-related reasons are irrelevant.

> The other problem you cite I consider to be an additional reason NOT to do it. If making good use of something requires expanding the scope of the change, that's a big red flag, especially in a language whose design is as conservative as Lua's.

I am afraid I cannot deduce unambiguously what "other problem" you reference here, neither do I understand what "change" and "expanding the scope" you mean - I certainly proposed none. Care to explain?

Cheers,
V.
Reply | Threaded
Open this post in threaded view
|

Re: Assignment Expressions in Lua

Coda Highland
On Tue, Jul 23, 2019 at 12:56 PM Viacheslav Usov <[hidden email]> wrote:
On Tue, Jul 23, 2019 at 7:19 PM Coda Highland <[hidden email]> wrote:

> And Lua doesn't have comprehensions OR lambdas.

As stated already, Python-related reasons are irrelevant.

It's relevant by virtue of the contrast between the two languages. If Lua HAD lambdas (or, to a lesser extent, comprehensions), then assignment expressions would make more sense.

Python syntax is built in such a way that assignment expressions are the only way to perform some tasks without using up an unreasonable amount of screen space. Lua syntax is different and does not derive nearly as much of a benefit, as there is literally not a single place in Lua where an assignment expression would save more than a single line of code. Clumsy constructions will remain clumsy; elegant constructions won't become more elegant.

Given that this discussion STARTED with pointing out a new feature in Python, it's rather difficult to interpret that as anything but a supporting argument.
 
> The other problem you cite I consider to be an additional reason NOT to do it. If making good use of something requires expanding the scope of the change, that's a big red flag, especially in a language whose design is as conservative as Lua's.

I am afraid I cannot deduce unambiguously what "other problem" you reference here, neither do I understand what "change" and "expanding the scope" you mean - I certainly proposed none. Care to explain?

Cheers,
V.

The latter half of your message, talking about multiple assignments and new semantics.

/s/ Adam
Reply | Threaded
Open this post in threaded view
|

Re: Assignment Expressions in Lua

Hugo Musso Gualandi



>a benefit, as there is literally not a single place in Lua where an
>assignment expression would save more than a single line of code.

One place where Lua has similar syntax to Pyhon is if-elseif statements. Assignment expressions let you avoid extra nesting here.

    if x := foo:match(p1) then
        -- A
    elseif x := foo:match(p2) then
        -- B
    elseif x := foo:match(p3) then
        -- C
    end

-- vs

    local x = foo:match(p1)
    if x then
        -- A
    else
        x = foo:match(p2)
        if x then
            -- B
        else
            x = foo:match(p3)
            if x then
                -- C
            end
        end
    end
end

Reply | Threaded
Open this post in threaded view
|

Re: Assignment Expressions in Lua

Coda Highland


On Tue, Jul 23, 2019 at 1:49 PM Hugo Musso Gualandi <[hidden email]> wrote:



>a benefit, as there is literally not a single place in Lua where an
>assignment expression would save more than a single line of code.

One place where Lua has similar syntax to Pyhon is if-elseif statements. Assignment expressions let you avoid extra nesting here.

    if x := foo:match(p1) then
        -- A
    elseif x := foo:match(p2) then
        -- B
    elseif x := foo:match(p3) then
        -- C
    end

-- vs

    local x = foo:match(p1)
    if x then
        -- A
    else
        x = foo:match(p2)
        if x then
            -- B
        else
            x = foo:match(p3)
            if x then
                -- C
            end
        end
    end
end

That's a valid point. I hadn't considered that specific example, although I would write it differently anyway:

local x = foo:match(p1)
if x then
  -- A
  return
end

x = foo:match(p2)
if x then
  -- B
  return
end

x = foo:match(p3)
if x then
  -- C
  return
end

(Replace "return" with whatever other control structure is appropriate for the context, of course. break is another good choice.)

I suppose by a strict interpretation this saves two lines per assignment expression instead of just the one that I had asserted, but there's a fairly good chance that the return statement would have been there anyway, if it returned a value.

Though it should be noted that in your example you still need a "local x" at the top to preserve the same semantics.

/s/ Adam
Reply | Threaded
Open this post in threaded view
|

Re: Assignment Expressions in Lua

Sergey Kovalev
In reply to this post by Pedro Tammela-2
вт, 23 июл. 2019 г. в 17:10, Pedro Tammela <[hidden email]>:
>
> In Python 3.8 there will be a new feature introducing Assignment Expressions[1]. One of the reasons for such feature is to improve code readability, among other things.
>
> Would assignment expressions improve Lua code readability?
No. Lua readablility is perfect.
There is right assignment in R, but other languages don't hurray to
introduce it.

Reply | Threaded
Open this post in threaded view
|

Re: Assignment Expressions in Lua

Jasper Klein
In reply to this post by Pedro Tammela-2
Op Tue, 23 Jul 2019 16:10:09 +0200 schreef Pedro Tammela
<[hidden email]>:

> In Python 3.8 there will be a new feature introducing Assignment
> Expressions[1]. One of the reasons for such feature is to improve code
> readability, among other things.
>
> Would assignment expressions improve Lua code readability?
>
> [1] https://www.python.org/dev/peps/pep-0572/

Maybe I missed the momentum of the discussion but I would like to see  
something similar in Lua.
It encourages to use RAII, and reduces the scope of the variable.

We already have in Lua some form of assignment expression in... for loops.
No one has been complaining about that.

Another example is C++17 that allows you to do something like:

if( auto foo = get_foo() ; foo.bar() == 42 )
{
   foo.baz( 1337 );
}

-- Jasper

Reply | Threaded
Open this post in threaded view
|

Re: Assignment Expressions in Lua

Coda Highland


On Thu, Jul 25, 2019 at 2:47 PM Jasper Klein <[hidden email]> wrote:
Op Tue, 23 Jul 2019 16:10:09 +0200 schreef Pedro Tammela
<[hidden email]>:

> In Python 3.8 there will be a new feature introducing Assignment
> Expressions[1]. One of the reasons for such feature is to improve code
> readability, among other things.
>
> Would assignment expressions improve Lua code readability?
>
> [1] https://www.python.org/dev/peps/pep-0572/

Maybe I missed the momentum of the discussion but I would like to see 
something similar in Lua.
It encourages to use RAII, and reduces the scope of the variable.

We already have in Lua some form of assignment expression in... for loops.
No one has been complaining about that.

Another example is C++17 that allows you to do something like:

if( auto foo = get_foo() ; foo.bar() == 42 )
{
   foo.baz( 1337 );
}

-- Jasper


Lua's for loops don't have assignment expressions. It's actually rather noteworthy compared to other programming languages -- neither the initialization or the increment is a statement.

The C++17 example also looks like something I would NEVER want to write. There's no compelling reason to put that on one line. Just kick the initializer out to the previous line, and add braces around it if you REALLY need the strict scoping.

/s/ Adam 
Reply | Threaded
Open this post in threaded view
|

Re: Assignment Expressions in Lua

Jasper Klein
Op Thu, 25 Jul 2019 21:54:13 +0200 schreef Coda Highland  
<[hidden email]>:

>>
> Lua's for loops don't have assignment expressions. It's actually rather
> noteworthy compared to other programming languages -- neither the
> initialization or the increment is a statement.
>
> The C++17 example also looks like something I would NEVER want to write.
> There's no compelling reason to put that on one line. Just kick the
> initializer out to the previous line, and add braces around it if you
> REALLY need the strict scoping.
>
> /s/ Adam

You don't have to write it. :-)

What about the next example?

local function f() return false end

for i = f() and 0 or 40, 42 do
   print( i )
end

print( i )

-- Jasper

Reply | Threaded
Open this post in threaded view
|

Re: Assignment Expressions in Lua

Francisco Olarte
In reply to this post by Coda Highland
Coda:

On Thu, Jul 25, 2019 at 9:54 PM Coda Highland <[hidden email]> wrote:
> On Thu, Jul 25, 2019 at 2:47 PM Jasper Klein <[hidden email]> wrote:
>> Another example is C++17 that allows you to do something like:
>> if( auto foo = get_foo() ; foo.bar() == 42 )
>> {
>>    foo.baz( 1337 );
>> }
...
> The C++17 example also looks like something I would NEVER want to write. There's no compelling reason to put that on one line. Just kick the initializer out to the previous line, and add braces around it if you REALLY need the strict scoping.

Well, I would never WANT to write that, but I wouldn't want to write
the alternative block for scoping either. They are the same, each
approach has its merits, and in some cases I would prefer it. I.e., if
instead of that synthetic example you have something like this (
shamelessly cut&pasted from cppreference ):

std::map<int, std::string> m;
...
if (auto it = m.find(10); it != m.end()) { return it->second.size(); }

I would prefer it to the extra block approach ( although I would drop
the if braces, as I tend to not use them in this case ). I would do ti
because I always unravel and indent, and the alternative:
{
    auto it = m.find(10);
    if(it != m.end()) return it->second.size();
} // No braces in if to make lien comparison fair in my style.

Does not gain readabality, just looses screen real state, which I
prefer to use for blank lones where I deem it useful.

Also, I can read the if as easy as "for(auto i=m.begin(),e=m.end();
i!=e;++i)', its idiomatic, but YMMV.

Francisco Olarte.

Reply | Threaded
Open this post in threaded view
|

Re: Assignment Expressions in Lua

Philippe Verdy
In reply to this post by Coda Highland
On Tue, Jul 23, 2019 at 11:10 AM Viacheslav Usov <[hidden email]> wrote:
Ultimately, Lua has its own problem where one cannot write
local x = foo(), y = bar(x)

 Of course you can rewrite it as:
  local x,y; x = foo(); y = bar(x)
It's not strictly equivalent because it first declares the variables x,y and initialize them to nil, before assigning them (a smart compiler may detect that and fix the nil initializer) preventing these declarations to be marked as read-only.
But the only safe way is:
  local x = foo(); local y = bar(x)

Except that the second declaration now depends on the modified scope for "x". It is not clear in your statement:
  local x = foo(), y = bar(x)
which value of x will be passed to call "bar(x)":
* (1) the value coming for the "foo()" initializer
* (2) or the value of "x" before the whole declaration ?

For the case (1), using two separate "local" statements is the solution

For the case (2) we don't have any clean Lua syntax to provide it, except (possibly) by changing the declaration order (which may have side effects when the initializers must be evaluated in a specified order). The work around is to use an anonymous function to evaluate all initializers at once:
  local x,y= (function() begin
      return foo(), bar(x) -- note that "x" does not refer to the "local x" which is still not visible
    end)()
But it is very verbose and possibly costly (unless the compiler is tuned and inlines these inline anonymous function calls); however these "local x,y" declarations can then be augmented with annotations to make them "constant" (readonly).