Trailing commas without parenthesis will always be interpreted in the wrong way because we have no way of knowing what the last comma is. It is impossible to implement. We should also strive to reduce the amount of ambiguity in the language, introducing more feels like going in the wrong direction.
Oooo, I did not know it had this inconsistencyā¦ I may need to start adding an ending optional ignored argument to all my multi-line (mostly macro) functions so I can keep ,
at the end.
The language has a ton of āsurprisingā cases like this already, this would actually remove one of the surprises if trailing commas were allowed inside parenthesis.
This is exactly why we canāt have trailing commas. You are doing a function call without parenthesis so with trailing commas itās ambiguous what the last argument is.
I hadnāt considered that.
However, it seems that the root cause of the ambiguity is that parentheses are optional. Thereās nothing ambiguous about this, is there?
# syntax error
ArgsDemo.normal_args(
10,
"blue",
)
If thereās a closing parenthesis, couldnāt the parser notice that and ignore the trailing comma?
We should also strive to reduce the amount of ambiguity in the language
I totally agree. Making parentheses required for function calls would remove the ambiguity, at some (arguable) aesthetic cost.
Indeed, Iād have the parser only accept trailing commas if it is inside parenthesis, otherwise itād be disallowed.
Indeed, Iād have the parser only accept trailing commas if it is inside parenthesis, otherwise itād be disallowed.
Yes - or inside []
.
Yes, thatās what we do inside brackets. But we donāt want to add it for function calls because, like I said earlier, we canāt support it for parenthesis-less functions and we feel it would be inconsistent and confusing to only support it for some function calls.
That would be a breaking change and would not possible until Elixir 2.0.
Iām not sure this topic is worth discussing any longer. I think everyone feels like the loss of the trailing comma is worth losing over losing optional parenthesis. I remember the backlash when elixir started warning about omitting parenthesis when piping and Iām fairly positive thats not something the community would be willing to trade.
I wonder why you would want trailing commas in function calls.
Functions in Elixir and Erlang are defined by their name and arity. A trailing comma in a function call seems to introduce unnecessary ambiguity when it comes to the arity of the called function.
Does foo(bar,)
refer to foo/1
or foo/2
with the second parameter accidentally omitted?
Multi-line, especially useful for macroās:
someMacro(
ModuleName,
a_very_long_argument_maybe_some_AST_for_the_macro,
or_maybe - a_set_of + math_that / needs_to * be_performed,
a: 1, # Or keyword list for those that like to use them without `[]`
b: 2,
c: 3,
)
Convoluted example, but it gets the point across. Plus it unifies the trailing comma syntax with []
and {}
and %{}
too, thus making things more consistent.
Iād never recommend a trailing comma in a single-liner, not in any of those.
But in this example, youāre still using the trailing comma for a keyword list and not for function parameters.
Each of those lines were intended to be exampled stand-alone. ^.^
Iāve always felt conflicted about the syntactic sugar that allows dropping brackets on keyword lists if theyāre the final parameter of a function call. For instance, try explaining to a newcomer to Elixir why this should happen:
IO.inspect("bar", label: "foo")
# foo: "bar"
# "bar"
IO.inspect(a: "bar", label: "foo")
# [a: "bar", label: "foo"]
# [a: "bar", label: "foo"]
This bit of sugar makes reading code more confusing for a somewhat cool (but not essential, as far as I know), feature. If it were up to me, I would enforce brackets around keyword lists (and continue to push replacing keyword lists with map). So the previous calls would unambiguously be:
IO.inspect("bar", [label: "foo"])
IO.inspect([a: "bar", label: "foo"])
In any case, I lean more towards the side of keeping the syntax between function calls with and without parens as close as possible, and donāt think trailing commas inside function calls with parens moves the language in a good direction.
If it were up to me, I would enforce brackets around keyword lists (and continue to push replacing keyword lists with map).
Absolutely thus. If Elixir did not start before maps were added to the BEAM, I bet that is what would have been done.
%{ one: "hello", + two: "goodbye", + three: "we meet again", }
Looking at this diff initially, it is hard to know that
two
did, in fact, not change at all. It was onlythree
that was added.
For this special case you can simply put the comma at the beginning of the line.
Elm is doing it this way and it feels not that bad to me.
%{
one: "hello"
, two: "goodbye"
+ , three: "we meet again"
}
Elm is doing it this way and it feels not that bad to me.
I prefer the OCaml way. ^.^
%{
one: "hello",
two: "goodbye",
+ three: "we meet again",
}
I.E. Trailing commaās. ^.^
(Although technically OCaml uses ;
instead of commaās to separate list and record elements, and commaās are used to separate tuple elements, and function arguments have no separators at all).
For this special case you can simply put the comma at the beginning of the line.
Elm is doing it this way and it feels not that bad to me.%{
one: āhelloā
, two: āgoodbyeā
- , three: āwe meet againā
}
Counterexample:
%{
+ zero: 0
+ ,one: "hello"
,two: "goodbye"
}
Anyway, this discussion is pointless, as I said earlier, since current version of the elixir formatter removes all trailing commas anyway.
There are tests in elixir/lib/elixir/test/elixir/code_formatter/containers_test.exs at 7f8136915fe249efa47a21a89ff0f04e880264fc Ā· elixir-lang/elixir Ā· GitHub that show that the removal of trailing comma is as expected.
Also I remember a discussion on core
or the issue tracker where @josevalim said, that trailing commans will be removed by the formatter and that this is not an option to discus.
So as much as Iād like to have them, in my opinion we can remove them from the parser in general, since the standard formatter, which we are all encouraged to use from 1.6s release on, will remove them anyway!
Counterexample:
Technically Elmās style is more like:
%{one: "hello"
,two: "goodbye"
}
As weird as that is, which would make your counterexample even more funky:
+ %{zero: 0
+ ,one: "hello"
,two: "goodbye"
}
^.^;
Wonderful idea!
Letās destroy all structure in code and make everything look like everything else!
clap
Letās destroy all structure in code an make everything look like everything else!
Structure is not syntax, the structure would remain identical here.
Iām happy to drop this issue - itās not the way I prefer, but itās not important.