This is exactly why I have the exact opposite rule as @vances’ one:
Never use lists in the
Args/InitArgsparameter forgen_*:start[_link](…)/init/1.
The erlang docs provide an example that includes…
start_link() ->
gen_server:start_link({local, ch3}, ch3, [], []).
…and…
init(_Args) ->
{ok, channels()}.
And I think that example, and other similar pieces of documentation, are misleading at best. Mainly for two reasons:
- Using an empty list if you don’t need to pass anything to
init/1may lead people to believe that you’re passing 0 arguments to theinitfunction (because sometimes arguments are passed down to some functions likesupervisor:start_child/2as lists. But that’s not true. With an empty list, you’re passing a single argument toinit/1, as usual. It’s just that in this case it’s a list. If you don’t need to pass any external values down toinit/1, I recommend the usage of an empty map (#{}), an empty tuple ({}), the atomundefined, or something even more explicit, like the atomno_arguments. - Calling the single parameter of
init/1Args. It’s not wrong, but again it may lead people to believe that since it’s written in plural, it has to be a list of arguments. When in reality it’s a single argument.
Using this example code to build servers has led more people than I count to write stuff like this…
-module my_server.
% …exports and everything else…
start_link(AParam) ->
gen_server:start_link(?MODULE, [AParam], []).
init(AParam) ->
…
Which is a code that compiles and it then fails mysteriously when it’s executed. It has produced many headaches over the years since that example was written.