|
12
|
Lua accepts since ever (as far I know) trailing commas in table definitions.
And this is good, since like most people experience sooner or later, when doing multilined stuff taking care of the last element is kinda a hassle.
However, I never understood, why trailing commas are not allowed in function calls.
Reasons are the same, sometimes a function call spawns several lines. This happens for me especially with functions taking variable length arguments like print() or write()
For example:
print( 'this is a string', 'another string', 'yet another string', -- note the comma here
)
I don't see any ambiguity added by this, or is there?
Patch is simple, maybe this one is a little naive, since explist() is called on various places. But works as far I tested*
--- lua-5.2.3/src/lparser.c 2013-04-12 20:48:47.000000000 +0200
+++ lua-5.2.3-comma/src/lparser.c 2014-06-04 16:24:35.958824924 +0200
@@ -812,6 +812,7 @@ int n = 1; /* at least one expression */ expr(ls, v); while (testnext(ls, ',')) { + if( ls->t.token == ')' ) break;
luaK_exp2nextreg(ls->fs, v); expr(ls, v); n++;
Kind regards, Axel
* test suite for available for 5.2.2 hangs my computer with extreme memory usage at the same position "testing strings and string library" with or without patch, dunno if my system is just too weak for it, I too impatient or I'm doing something wrong.
|
|
On 04/06/2014 11:48, Axel Kittenberger
wrote:
Lua accepts since ever (as far I know) trailing commas in
table definitions.
And this is good, since like most people experience
sooner or later, when doing multilined stuff taking care of
the last element is kinda a hassle.
However, I never understood, why trailing commas are not
allowed in function calls.
Reasons are the same, sometimes a function call spawns
several lines. This happens for me especially with functions
taking variable length arguments like print() or write()
For example:
print(
'this is a string',
'another string',
'yet another string', -- note the comma here
)
I don't see any ambiguity added by this, or is there?
Patch is simple, maybe this one is a little naive,
since explist() is called on various places. But works as far
I tested*
--- lua-5.2.3/src/lparser.c 2013-04-12
20:48:47.000000000 +0200
+++ lua-5.2.3-comma/src/lparser.c 2014-06-04
16:24:35.958824924 +0200
@@ -812,6 +812,7 @@
int n = 1; /* at least one expression */
expr(ls, v);
while (testnext(ls, ',')) {
+ if( ls->t.token == ')' ) break;
luaK_exp2nextreg(ls->fs, v);
expr(ls, v);
n++;
Kind regards, Axel
* test suite for available for 5.2.2 hangs my computer with
extreme memory usage at the same position "testing strings and
string library" with or without patch, dunno if my system is
just too weak for it, I too impatient or I'm doing something
wrong.
That just drops the comma no? I think something like
"print(somemultireturnfunc(),)" should do the same as
"print((somemultireturnfunc()))" instead...
|
|
On Wed, Jun 4, 2014 at 9:48 AM, Axel Kittenberger < [hidden email]> wrote:
> However, I never understood, why trailing commas are not allowed in function
> calls.
I'd like to see that too.
(or to know if there's any reason behind it)
--
Javier
|
|
On 4 June 2014 11:55, Thiago L. < [hidden email]> wrote:
> That just drops the comma no? I think something like
> "print(somemultireturnfunc(),)" should do the same as
> "print((somemultireturnfunc()))" instead...
The presence of an extra comma would leave me second-guessing the
behavior on multiple returns too. In any case, it should do the same
as the table constructor. Went to check what the table constructor
does:
Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio
> function f() return 1, 2 end
> t = { f() }
> print(t[1], t[2])
1 2
> u = { f(), }
> print(u[1], u[2])
1 2
> v = { f(), 3 }
> print(v[1], v[2])
1 3
>
So, yes, if function calls were to accept a trailing comma, I think
they should just drop the comma and not impose special behavior on
multiple returns, for consistency with the table constructor.
-- Hisham
|
|
2014-06-04 16:48 GMT+02:00 Axel Kittenberger < [hidden email]>:
> Lua accepts since ever (as far I know) trailing commas in table definitions.
>
> And this is good, since like most people experience sooner or later, when
> doing multilined stuff taking care of the last element is kinda a hassle.
>
> However, I never understood, why trailing commas are not allowed in function
> calls.
>
> Reasons are the same, sometimes a function call spawns several lines. This
> happens for me especially with functions taking variable length arguments
> like print() or write()
>
> For example:
>
> print(
> 'this is a string',
> 'another string',
> 'yet another string', -- note the comma here
> )
>
> I don't see any ambiguity added by this, or is there?
More generally, "lexical void" inside an argument list could mean nil.
That is something that I (when in a bikeshedding mood) have sometimes
missed, with some library functions where I use seldom use the early
arguments, e.g.
load(source,,,MY_ENV)
But now, in your example, I don't suppose you want
print(
'this is a string',
'another string',
'yet another string', -- note the comma here
)
to mean
print('this is a string', 'another string', 'yet another string', nil )
or would you?
|
|
On 04/06/2014 12:13, Hisham wrote:
> On 4 June 2014 11:55, Thiago L. < [hidden email]> wrote:
>> That just drops the comma no? I think something like
>> "print(somemultireturnfunc(),)" should do the same as
>> "print((somemultireturnfunc()))" instead...
> The presence of an extra comma would leave me second-guessing the
> behavior on multiple returns too. In any case, it should do the same
> as the table constructor. Went to check what the table constructor
> does:
>
> Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio
>> function f() return 1, 2 end
>> t = { f() }
>> print(t[1], t[2])
> 1 2
>> u = { f(), }
>> print(u[1], u[2])
> 1 2
>> v = { f(), 3 }
>> print(v[1], v[2])
> 1 3
> So, yes, if function calls were to accept a trailing comma, I think
> they should just drop the comma and not impose special behavior on
> multiple returns, for consistency with the table constructor.
>
> -- Hisham
>
But code golfing... :(
|
|
> However, I never understood, why trailing commas are not allowed in
> function calls.
One argument for not supporting this is that argument lists are almost never
generated automatically, which was the original motivation for supporting
trailing commas in table constructors, as this simplifies code generation.
Another is that argument lists in practice are never very long.
|
|
Andrew> With argument lists, it would be ambiguous as to whether or not a nil was being placed there and that is not the same thing.
There is no implicit nil beyond the last comma, by definition. It was never valid code before, so there is no breakage. What Dirk posted before as lexical void meaning nil, was a suggestion. I'm not hot for that, since I don't think it helps readability, but I wouldn't mind either if others like it.
Luiz> ... as this simplifies code generation.
I don't know what people are autogenerating, but why wouldn't they autogenerate function calls when generating code, but only tables? I at least do the former :-) But honestly I never cared so much about that, the extra if to prepend a comma in the output loop when index is greater than 1 never was that much a hassle for me. Its more hand written code where I don't like to have failing code if forgetting to remove the trailing comma when removing what was previously the last entry.
Luiz> Another is that argument lists in practice are never very long.
Well there is only one trailing comma independently if the list was short or long. Its always one that is or isn't an issue. But I guess you mean cases where going multilined. write() is a case where it happens often, especially in luatex I experienced long argument lists with write. And there maintaining the last comma there or not there by hand is cumbersome.
Anyway, its all not too important, going to live a happy life even without trailing commas in functions :-) Just thought this would be something rather easy to fix. I also don't know of any other language that supports this, but Lua was cooler than most others anyway.
|
|
On Wed, Jun 4, 2014 at 12:13 PM, Axel Kittenberger < [hidden email]> wrote:
> I also don't know of any other language that supports this
python does:
def s(a,b):
return a+b
s(1,2)
=> 3
s(1,2,)
=> 3
s(1,2,3)
=> TypeError: s() takes exactly 2 arguments (3 given)
--
Javier
|
|
In reply to this post by Luiz Henrique de Figueiredo
* Luiz Henrique de Figueiredo:
> One argument for not supporting this is that argument lists are almost never
> generated automatically, which was the original motivation for supporting
> trailing commas in table constructors, as this simplifies code generation.
>
> Another is that argument lists in practice are never very long.
And they are rarely split as one item per line. For tables, the
trailing comma reduces visual clutter in diffs if there's one item per
line.
|
|
On Wednesday, June 04, 2014 05:15:23 PM Dirk Laurie wrote:
> More generally, "lexical void" inside an argument list could mean nil.
> That is something that I (when in a bikeshedding mood) have sometimes
> missed, with some library functions where I use seldom use the early
> arguments, e.g.
>
> load(source,,,MY_ENV)
I like this. And on the left side too.
first,,third = something()
Assigns the first and third values while dropping the second without having to
assign a dummy variable.
> But now, in your example, I don't suppose you want
> to mean
>
> print('this is a string', 'another string', 'yet another string', nil )
>
> or would you?
You can have both. The formal definition of an unnamed element in a comma list
is "nothing". That is,
print() -- is not the same as
print(nil) -- thus
print(,) -- is not the same as
print(nil,nil)
It's not that you're ignoring the last comma when there's no variable after
it, you're implying the last comma after a variable name. Then the number of
arguments to the function is equal to the number of commas.
--
tom < [hidden email]>
|
|
> load(source,,,MY_ENV)
> first,,third = something()
The idiom in these cases would be
load(source,_,_,MY_ENV)
first,_,third = something()
Perhaps it'd be helpful to have a second predeclared local named "_",
as a cheap throw-away variable...
|
|
On 6/4/2014 6:01 PM, Luiz Henrique de Figueiredo wrote:
>> load(source,,,MY_ENV)
>> first,,third = something()
> The idiom in these cases would be
>
> load(source,_,_,MY_ENV)
> first,_,third = something()
>
> Perhaps it'd be helpful to have a second predeclared local named "_",
> as a cheap throw-away variable...
>
Rather like Go, where _ is predeclared for the same purpose (would be
surprised if they didn't get the idea from Lua). What does everyone
think about also outlawing _ as an rvalue, as Go does?
This would firmly establish _ as a throw-away variable, but is it worth
the internal complexity to enforce it? Perhaps the middle way of
predeclaring but not enforcing is best.
|
|
On Jun 4, 2014 11:31 PM, "Mike Nelson" <[hidden email]> wrote:
> What does everyone think about also outlawing _ as an rvalue, as Go does?
It would go against the "mechanisms, not policies" mantra of the language.
|
|
On Wed, Jun 4, 2014 at 7:30 PM, Mike Nelson < [hidden email]> wrote:
> On 6/4/2014 6:01 PM, Luiz Henrique de Figueiredo wrote:
>>>
>>> load(source,,,MY_ENV)
>>> first,,third = something()
>>
>> The idiom in these cases would be
>>
>> load(source,_,_,MY_ENV)
>> first,_,third = something()
>>
>> Perhaps it'd be helpful to have a second predeclared local named "_",
>> as a cheap throw-away variable...
>>
> Rather like Go, where _ is predeclared for the same purpose (would be
> surprised if they didn't get the idea from Lua). What does everyone think
> about also outlawing _ as an rvalue, as Go does?
> This would firmly establish _ as a throw-away variable, but is it worth the
> internal complexity to enforce it? Perhaps the middle way of predeclaring
> but not enforcing is best.
The first of Luiz's examples uses _ as an rvalue.
/s/ Adam
|
|
Am 05.06.2014 05:01 schröbte Coda Highland:
> On Wed, Jun 4, 2014 at 7:30 PM, Mike Nelson < [hidden email]> wrote:
>> On 6/4/2014 6:01 PM, Luiz Henrique de Figueiredo wrote:
>>>>
>>>> load(source,,,MY_ENV)
>>>> first,,third = something()
>>>
>>> The idiom in these cases would be
>>>
>>> load(source,_,_,MY_ENV)
>>> first,_,third = something()
>>>
>>> Perhaps it'd be helpful to have a second predeclared local named "_",
>>> as a cheap throw-away variable...
>>>
>> Rather like Go, where _ is predeclared for the same purpose (would be
>> surprised if they didn't get the idea from Lua). What does everyone think
>> about also outlawing _ as an rvalue, as Go does?
>> This would firmly establish _ as a throw-away variable, but is it worth the
>> internal complexity to enforce it? Perhaps the middle way of predeclaring
>> but not enforcing is best.
>
> The first of Luiz's examples uses _ as an rvalue.
... and if you swap those two examples you will get weird results, so
that would actually be an argument _against_ using `_` as an rvalue (at
least for normal code).
And predeclaring is not really useful. Usually you do
local first,_,third = something()
anyway, and if you predeclare `first` and `third`, you can add `_` to
the list there as well ...
>
> /s/ Adam
>
Philipp
|
|
In reply to this post by Luiz Henrique de Figueiredo
On Wednesday, June 04, 2014 10:01:13 PM Luiz Henrique de Figueiredo wrote:
> The idiom in these cases would be
>
> load(source,_,_,MY_ENV)
> first,_,third = something()
>
Of course. But if the lines were reversed you'd have a problem. I'm sure
everyone knows not to trust `_` as a rvalue and explicitly writes `nil`. If
`_` were reserved as a placeholder name then as a lvalue it's immediately
forgotten, and as a rvalue it evaluates to `nil`. But then what's the
difference between this and what Dirk and I suggested with empty items in the
comma list? It's not merely syntactic sugar because you're indicating the
value is going to be discarded immediately. The compiler then knows it doesn't
need to keep that register slot around unlike the `local _`. Not to mention
gcing the value earlier.
I'm pretty sure there are sources out there that use `_` for something other
than a placeholder lvalue. Any change to how it's handled would break
someone's code.
Alternately allow `nil` as a lvalue that acts as the bit bucket.
--
tom < [hidden email]>
|
|
On Wed, Jun 4, 2014 at 9:56 PM, Tom N Harris < [hidden email]> wrote:
> Alternately allow `nil` as a lvalue that acts as the bit bucket.
I like this best.
/s/ Adam
|
12
|