Idiomatic Erlang

7330b65ea54e1b90a987a552e5c5cf32?s=47 Mark Allen
November 13, 2017

Idiomatic Erlang

Some guidelines to consider when you're doing greenfield Erlang development.

7330b65ea54e1b90a987a552e5c5cf32?s=128

Mark Allen

November 13, 2017
Tweet

Transcript

  1. Idiomatic Erlang MARK ALLEN MRALLEN1@YAHOO.COM @BYTEMEORG

  2. Style suggestions u Use inline type specifications and documentation tools

    u Use list comprehensions u Use explicit functions in higher order functions u Don’t nest case statements u Use sweet syntactic sugar for maps and record pattern matching u Reply to unknown gen_server call messages with a weird answer. (Why?) u Use erlang:error/2 instead of error/1 u Start new projects using rebar3 templates u Make your editor help you (find and use Erlang plugins for your code editor) u Finite state machines are powerful – exploit their power
  3. Example code -spec repeat( FunName :: atom() | function(), Args

    :: [ term() ], Count :: pos_integer() ) -> Result :: term() | { error, Reason :: term() }. %% @doc This function repeats calls to a function name which may fail %% given by the FunName parameter for Count number of times. repeat(_FunName, _Args, 0) -> {error, count_reached_zero); repeat(FunName, Args, Count) when is_atom(FunName) -> do_repeat({?MODULE, FunName}, Args, Count); repeat(FunName, Args, Count) when is_function(FunName) -> do_repeat(FunName, Args, Count); repeat(Other, _Args, _Count) -> erlang:error({error, badarg}, [Other, Args]). do_repeat(Fun, Args, C) -> try erlang:apply(Fun, Args) catch _:_ -> repeat(FunName, Args, C – 1) end.
  4. Type specifications u Dialyzer is a type analysis tool for

    Erlang/Elixir. u You give dialyzer hints by providing a type specification for your (public) functions. u They help remind you what the arguments to a function are and what sorts of output might be returned. u Dialyzer can help you spot instances in your code when the specification is not true.
  5. List comprehensions u Powerful and compact way to filter and

    iterate over a collection of items in a list. u Can replace lists:map and lists:filtermap [[ prepare_valid_element(E) || E <- List, E /= undefined ]]. lists:filtermap( fun(E) when E /= undefined -> {true, prepare_valid_element(E)}; (_E) -> false end, List).
  6. Explicit function names u Using explicit function names gives two

    benefits: u Much better stack traces u Easy to write unit tests for the whole function and the higher order function lists:map(fun(X) -> X*X end, lists:seq(1,5)). lists:map(fun double/1, lists:seq(1,5)). double(X) -> X*X.
  7. Don’t nest case statements u They’re hard to read and

    hard to reason about. u Use guard clauses and explicit functions. case foo(Arg1, Arg2) of true -> case of bar(Arg2) of true -> min(1, Arg1); false -> 100 end; false -> {{error, badarg}, Arg1} end.
  8. Don’t nest case statements u They’re hard to read and

    hard to reason about. u Use guard clauses and explicit functions. case foo(Arg1, Arg2) of true -> case of bar(Arg2) of true -> min(1, Arg1); false -> 100 end; false -> {{error, badarg}, Arg1} end.
  9. Don’t nest case statements case foo(Arg1, Arg2) of true ->

    test_arg2(Arg1, Arg2) false -> {{error, badarg}, Arg1} end. test_arg2(Arg1, Arg2) -> case bar(Arg2) of true -> min(1, Arg1); false -> 100 end.
  10. Sweet syntactic sugar handle_call({incr, _Arg}, _From, S = #state{ state

    = lock }) -> {reply, {error, locked}, S}; handle_call({incr, Arg}, _From, S = #state{ cnt = C }) -> {reply, ok, S#state{ cnt = C + Arg }}. incr_foo(V, Map = #{ foo := Current }) -> Map#{ foo := Current + V }.
  11. Use weird reply to unknown message handle_call(Call, From, State) ->

    ?LOG("Unknown call ~p from ~p!!”, [Call, From]), {reply, unknown_call_message_die_die_die, State}.
  12. Use erlang:error/2 u Provides the specific bad argument along with

    the error atom in a stack trace. This is really helpful! u Demo
  13. Remainder u Use rebar3 templates to start new projects u

    Make your editor help you! u Don’t ignore finite state machines! They provide great clarity/insight into your programming intentions.