Do you want to pick up from where you left of?
Take me there

Erlang Interoperability

One of the added benefits to building on top of the Erlang VM (BEAM) is the plethora of existing libraries available to us. Interoperability allows us to leverage those libraries and the Erlang standard lib from our Elixir code. In this lesson we’ll look at how to access functionality in the standard lib along with third-party Erlang packages.

Standard Library

Erlang’s extensive standard library can be accessed from any Elixir code in our application. Erlang modules are represented by lowercase atoms such as :os and :timer.

Let’s use :timer.tc to time execution of a given function:

defmodule Example do
  def timed(fun, args) do
    {time, result} = :timer.tc(fun, args)
    IO.puts("Time: #{time} μs")
    IO.puts("Result: #{result}")
  end
end

iex> Example.timed(fn (n) -> (n * n) * n end, [100])
Time: 8 μs
Result: 1000000

For a complete list of the modules available, see the Erlang Reference Manual.

Erlang Packages

In a prior lesson we covered Mix and managing our dependencies. Including Erlang libraries works the same way. In the event the Erlang library has not been pushed to Hex you can refer to the git repository instead:

def deps do
  [{:png, github: "yuce/png"}]
end

Now we can access our Erlang library:

png =
  :png.create(%{:size => {30, 30}, :mode => {:indexed, 8}, :file => file, :palette => palette})

Notable Differences

Now that we know how to use Erlang we should cover some of the gotchas that come with Erlang interoperability.

Atoms

Erlang atoms look much like their Elixir counterparts without the colon (:). They are represented by lowercase strings and underscores:

Elixir:

:example

Erlang:

example.

Strings

In Elixir when we talk about strings we mean UTF-8 encoded binaries. In Erlang, strings still use double quotes but refer to char lists:

Elixir:

iex> is_list('Example')
true
iex> is_list("Example")
false
iex> is_binary("Example")
true
iex> <<"Example">> === "Example"
true

Erlang:

1> is_list('Example').
false
2> is_list("Example").
true
3> is_binary("Example").
false
4> is_binary(<<"Example">>).
true

It’s important to note that many older Erlang libraries may not support binaries so we need to convert Elixir strings to char lists. Thankfully this is easy to accomplish with the to_charlist/1 function:

iex> :string.words("Hello World")
** (FunctionClauseError) no function clause matching in :string.strip_left/2

    The following arguments were given to :string.strip_left/2:

        # 1
        "Hello World"

        # 2
        32

    (stdlib) string.erl:1661: :string.strip_left/2
    (stdlib) string.erl:1659: :string.strip/3
    (stdlib) string.erl:1597: :string.words/2

iex> "Hello World" |> to_charlist() |> :string.words
2

Variables

In Erlang, variables begin with an uppercase letter and re-binding is not allowed.

Elixir:

iex> x = 10
10

iex> x = 20
20

iex> x1 = x + 10
30

Erlang:

1> X = 10.
10

2> X = 20.
** exception error: no match of right hand side value 20

3> X1 = X + 10.
20

That’s it! Leveraging Erlang from within our Elixir applications is easy and effectively doubles the number of libraries available to us.

Caught a mistake or want to contribute to the lesson? Edit this lesson on GitHub!