Are There Any Important Differences Between These Two Code Approaches?

Viewed 108

I've got some Elixir code on which I was working with some colleagues. The very simplified code below should demonstrate the essence of the question I'm trying to resolve.

defmodule DemonstrateQuestion do
   def fh(), do: :unknown
   def fh("A"), do: :a
   def fh("B"), do: :b
   def fh(_), do: :unknown
end

defmodule AlternateBehavior do
   def fh(_\\nil)
   def fh("A"), do: :a
   def fh("B"), do: :b
   def fh(_), do: :unknown
end

I prefer the approach in DemonstrateQuestion because it explicitly calls out the zero arity function head. But I cannot detect any functional difference between DemonstrateQuestion and AlternateBehavior. So my question is, is there a valid technical reason (e. g. calling out the zero arity function head helps Elixir to generate better byte code) to prefer one approach or the other?

1 Answers

One can get the erlang code back out of BEAM file if Code.compiler_options(debug_info: true) has been set (fwiw, in the iex session it’s set by default.)

First, we need to compile the input to BEAMs. The simplest way would be to create the projects with mix new, create config/config.exs with the single line Code.compiler_options(debug_info: true), and compile the project.

Then run iex and do the following magic:

{:ok, {_, [{:abstract_code, {_, dq}}]}} =
  :beam_lib.chunks(
    '_build/dev/lib/PROJECT_NAME/ebin/Elixir.DemonstrateQuestion.beam',
    [:abstract_code])
dq_code = :erl_prettypr.format(:erl_syntax.form_list(dq))
dq_code |> to_string() |> IO.puts()

You’ll get back the erlang source. Notice

-export(['__info__'/1, fh/0, fh/1]).

...

fh() -> unknown.

fh(<<"A">>) -> a;
fh(<<"B">>) -> b;
fh(_) -> unknown.

For the alternate case it’d give back

fh() -> fh(nil).

fh(<<"A">>) -> a;
fh(<<"B">>) -> b;
fh(_) -> unknown.

That said, the alternate approach gives a neglectable subtle overhead for fh/0: a superfluous function call fh(nil) instead of the direct return of :unknown.

Related