lolwat.
If thatâs your biggest gripe about Elixir, then I think Elixir is doing a pretty great job
Theyâre probably allowing this for the same reasons that Elixir doesnât mind if you put a trailing comma at the end of a Map:
%{
one: "hello",
two: "goodbye",
}
Adding an extra key to this map would lead to:
%{
one: "hello",
two: "goodbye",
three: "we meet again",
}
Where the diff would simply be:
%{
one: "hello",
two: "goodbye",
+ three: "we meet again",
}
If it didnât allow for a trailing comma, then you would have to write the initial map as:
%{
one: "hello",
two: "goodbye"
}
Then, to add another key, you would need to add the comma to the 2nd key-value pair and add the third line, which would result in a diff showing one line modified (two
) and one line added three
.
%{
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 only three
that was added.
So I can see sense for allowing this sort of thing in PHPâs function calls⊠and to that extent, in Elixirâs calls too. Just to make diffs a little easier to mentally parse.
It feels like making Elixir do this wouldnât be too hard a task, but I wouldnât even know where to begin myself.
Thanks for sharing, @ryanwinchester.
PHP allows a set of things Iâm very glad Elixir doesnâtâŠ
Wouldnât this make Elixirâs syntax ambiguous? For example, how would you parse this:
f a, b, c,
d e
as
f(a, b, c, d e)
or
f(a, b, c,)
d(e)
Or would the trailing comma be allowed only if there were parenthesis?
No trailing comma please. The PHP era is over. Go Elixir Go.
I donât get it⊠Correct me if Iâm wrong but you already can do that in ElixirâŠ
# this is valid...
my_variable = div(
10,
2
)
Seems more progressive to remove the need for commas altogether - âless is moreâ. Clojure (LISP) made me aware of that and even GraphQL picked up on the idea:
####2.15 Insignificant Commas
Comma ::
,
Similar to white space and line terminators, commas (,) are used to improve the legibility of source text and separate lexical tokens but are otherwise syntactically and semantically insignificant within GraphQL query documents.
Nonâsignificant comma characters ensure that the absence or presence of a comma does not meaningfully alter the interpreted syntax of the document, as this can be a common userâerror in other languages. It also allows for the stylistic use of either trailing commas or lineâterminators as list delimiters which are both often desired for legibility and maintainability of source code.
Yes, go lisp syntax instead. The simplest syntax of them all. Of course it is a little anti-elixir in that it enforces parentheses while elixir allows you to not use them.
Oh now I get it ^^ thank you!
Hum it seems useless hahahaha
Iâd like a lisp that would compile into Elixir modules. Itâs not very hard to do, only a little boring because of little details such as designing a sensible standard library, tooling, sourcemaps, etc. You would know, of course xD
Why Elixir and not Erlang?
First, being able to interoperate with Elixir macros is huge, and Elixirâs AST oddities (like do
blocks and the internal __block__
node) map relatively well to lispâs progn
or the scheme equivalents. With one or two helper macros, one could use Phoenix as is. This interoperability alone makes ir worth it to compile to Elixir instead of Erlang. Phoenixâs âgutsâ very well designed (PubSub, Channels, Presence), although one might dislike some surface characteristics. And Phoenix is so easy to customize that it doesnât matter anyway.
Phoenix was basically the only reason I went for Elixir instead of LFE. One can debate the timeless beauty of lisp until the cows come home, but Elixir has Phoenix and Phoenix has channels, and channels are shiny and modern and won me over xD
Second, compiling to Elixir means we can use elixirâs tooling: Mix as a build tool (with a custom compiler), ExDoc for documentation and the new BEAM chunks for documentation and better error reporting in pattern matches.
Iâm not familiar with the Erlang equivalents (rebar and erldoc), but again, Mix makes it easy to integrate with Elixir libraries.
@OvermindDL1 has been working on a toy implementation, which nonetheless has read macro support.
This project on Github also implements a lisp interpreter on Elixir with static types and HM type inference: https://github.com/tpoulsen/terp
Trailing comas would only be allowed with parenthesis.
Hear hear! Full ML style would be really nice actually. ^.^
Iâd already have that done if I had time, maybe during thanksgiving or christmas breaksâŠ
Eh, itâd be easy enough for a lispây erlang to access elixir macroâs and transform them to itâs internal syntax, though that would be more work over just going to elixir to begin with. ^.^;
Ditto to be honest. If not for Phoenix and Hex Iâd be using erlang and lfe (probably together) as I prefer both of their syntaxâs (and lfeâs substantial features, though it still needs read-macroâs! ^.^) better.
Yeah read-macro support (even scoped!) is nicely trivial to do. ^.^
Iâve actually been played with an idea to do a Staged compilation pipeline of LISP, this is how macro systems work in most languages (not lispâs) and although it is âslightlyâ more limiting, it allows me to output (even typed) âfinal generated codeâ much more easily.
This thing looks really cool, I need to play with it, it looks similar to what I was already creating. ^.^;
Yup. Iâd like it in Elixir especially as I tend to do multi-line function calls in many cases (because macroâs, so I cannot just split them out into different bindings).
(Side comment, OCaml has got an Elixir-like Macro system via a PPX just recently ^.^)
I found this thread because I was independently wishing for trailing comma support for arguments.
I have an Ecto query like this:
from recipe in query,
join: id_and_rank in matching_recipe_ids_and_ranks(ts_query_string),
on: id_and_rank.id == recipe.id,
order_by: [desc: id_and_rank.rank]
If I want to see what the results look like without the order_by:
, I canât just comment out that line; I have to also remove the trailing comma on the previous line.
Similarly, I canât just add a second order_by:
without adding a comma to the existing line.
I also would like for Elixir to be consistent in how it treats list vs non-list arguments with regard to trailing commas.
defmodule ArgsDemo do
def list_args(args \\ []), do: IO.inspect args
def normal_args(arg1, arg2), do: IO.inspect [arg1, arg2]
end
end
# works fine, because lists can have trailing args
ArgsDemo.list_args(
[
{:size, 10},
{:color, "blue"},
]
)
# works fine, because it's syntax sugar for a list
ArgsDemo.list_args(
size: 10,
color: "blue",
)
# syntax error
ArgsDemo.normal_args(
10,
"blue",
)
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.
In the code below, why would the parser not think other_expression()
is the last argument of the from
function call?
from recipe in query,
join: id_and_rank in matching_recipe_ids_and_ranks(ts_query_string),
on: id_and_rank.id == recipe.id,
order_by: [desc: id_and_rank.rank],
other_expression()
Even though we were at a point where trailing commas were supported by the grammar, they will be removed by the formatter⊠At least this is for map and list literals. I see no reason why the formatter should behave differently on function arguments.
But since Iâm forced to use them in go
, I really got used to them (and that they do nmot create much noice on diffs)[1].
[1] go fmt
has the bad habbit to align values in multiline struct literals, which creates a lot of diff-noise thoughâŠ
Do you mean âthis is why we canât have trailing commas in parenthesis-less callsâ? I see no argument in your reply for disallowing them in parenthesis calls.
Yes, the example used a non-parenthesis call so thatâs what I commented on. We shouldnât allow them with parenthesis either because that would be inconsistent and prone to mistakes because the assumption is that the same syntax is allowed for all calls regardless of parenthesis.
In my mind allowing trailing parenthesis would be more consistent as
-
trailing parenthesis are allowed in lists, tuples, and maps (in fact this inconsistency is why I would like trailing commas in function calls in the first place)
-
trailing commas are allowed in bracketless keyword lists at the end of function calls:
foo(
bar,
baz: 1,
)
Furthermore, it is not clear to me why trailing commas must be explicitly disallowed in parenthesis-less function calls. Sure, they would never be useable because they would almost always be interpreted as they are now, but if that inconsistencyâwhich already exists in other parts of the languageâbothers you, striking parenthesis-y trailing commas is not the only solution. (Parenthesis are commonly used to resolve abiguity anyways, this should be nothing new.)
Lastly, when you say
are you speaking from experience? I ask because that being an issue is not at all obvious to me. As mentioned above, the assumption that the same syntax is allowed for all calls regardless of parenthasis does not hold: trailing commas are allowed at the end of bracketless keyword lists inside parenthasis calls, but not inside parenthasis-less.