Dark corner of Erlang syntax

Generally I like maybe even love Erlang syntax, but some result of its flexibility and simplicity hit me hard today. I have a supervisor starting several gen_servers, this is part of the supervisor configuration in its init function:

#{
    id => server_1,
    start => {gen_server, start_link, [{local, server_1}, server_1, [], []]},
    modules => [server_1]
},
#{
    id => server_2,
    start => {gen_server, start_link, [{local, server_2}, server_2, [], []]},
    modules => [server_2]
}
#{
    id => server_3,
    start => {gen_server, start_link, [{local, server_3}, server_3, [], []]},
    modules => [server_3]
}

The server_2 was not running, and after a long and painful hour finally I have noticed missing comma between server_2 and server_3. Due to the way Erlang syntax works this was interpreted as two maps, not an error. This typo is the reason why server_2 silently does not start!

Maybe we could have a warning when a literal map is overridden with another literal map?

10 Likes

This pops up from time to time, indeed.
I wrote an article about it once…

9 Likes

Could it be changed to a warning, perhaps?

8 Likes

Yes, I think a warning is better as it is not really an error.

6 Likes

Yes the syntax is legitimate and it cannot be an error. But warning would be very useful. I do not think the situation where one map literal overrides another map literal is used often, so warning should not introduce any significant problems. And of course there should be a way to disable the warning. But I think it would be a welcome addition - after all it is not very common thing in languages when omitting a comma between two constructs silently turns them into another unintended legitimate construct.

2 Likes

A legitimate use-case is using a macro as a “template”:

-define(T, #{ module => ?MODULE }).
% ...
?T#{ additional_info => 1 }.
2 Likes

And that, depending on when the check is made, will likely not trigger the warning.
For instance, if the warning comes from rebar3_lint, then Elvis’ parser won’t see an instance of #{…}#{…} there.
BTW, @wojtek : There is a ticket to write this rule: Don't use map()map() syntax · Issue #157 · inaka/elvis_core · GitHub
I mean… in case you feel like sending a pull request… :roll_eyes:

4 Likes