This reference is aimed at allowing you to comfortably read erlang documentation and consume terms printed in Erlang format. It does not aim at allowing you to write Erlang code.
This is a modified version of http://elixir-lang.org/crash-course.html
Erlang and Elixir have the same data types for the most part, but there are a number of differences.
In Erlang, an atom
is any identifier that starts with a lowercase letter, e.g. ok
, tuple
, donut
.
Identifiers that start with a capital letter are always treated as variable names.
Elixir, on the other hand, uses the former for naming variables, and the latter are treated as atom aliases.
Atoms in Elixir always start with a colon :
.
Erlang
im_an_atom.
me_too.
Im_a_var.
X = 10.
Elixir
:im_an_atom
:me_too
im_a_var
x = 10
Module # this is called an atom alias; it expands to :'Elixir.Module'
It is also possible to create atoms that otherwise wouldn't be allowed (for example with a space, or starting with a number or an uppercase character). The syntax is different between the two languages:
Erlang
is_atom(ok). %=> true
is_atom('0_ok'). %=> true
is_atom('Multiple words'). %=> true
is_atom(''). %=> true
is_atom('_'). %=> true
Elixir
is_atom :ok #=> true
is_atom :'ok' #=> true
is_atom Ok #=> true
is_atom :"Multiple words" #=> true
is_atom :"" #=> true
is_atom :_ #=> true
Modules are atoms. Elixir uses additional syntactic sugar to distinguish regular module names from other atoms:
iex> :"Elixir.Foo.Bar" == Foo.Bar
Whenever you see reference to module lists
in Erlang, it will be module :lists
in Elixir.
To write Elixir style module name in Erlang, you need to use the escaping technique described above -
so 'Elixir.Foo.Bar'
in Erlang is equivalent to :"Elixir.Foo.Bar"
and Foo.Bar
in Elixir.
The syntax for tuples is the same in both languages, but the APIs are different. Elixir attempts to normalize Erlang libraries in a way that:
- The
subject
of the function is always the first argument. - All data structures functions employ zero-based access.
That said, Elixir does not import the default element
and setelement
functions,
but instead provides elem
and put_elem
:
Erlang
element(1, {a, b, c}). %=> a
setelement(1, {a, b, c}, d). %=> {d, b, c}
Elixir
elem({:a, :b, :c}, 0) #=> :a
put_elem({:a, :b, :c}, 0, :d) #=> {:d, :b, :c}
Elixir has a shortcut syntax for binaries:
Erlang
is_atom('Hello'). %=> true
is_list("Hello"). %=> true
is_binary(<<"Hello">>). %=> true
Elixir
is_atom :"Hello" #=> true
is_list 'Hello' #=> true
is_binary "Hello" #=> true
is_binary <<"Hello">> #=> true
<<"Hello">> === "Hello" #=> true
In Elixir, the word string means a UTF-8 binary and there is a String
module that works on such data.
Elixir also expects your source files to be UTF-8 encoded.
On the other hand, string in Erlang refers to charlists and there is a :string
module,
that's not UTF-8 aware and works mostly with what we call in Elixir charlists.
This means "a string"
in Erlang, will be 'a string'
in Elixir
and <<"a binary">>
in Erlang will be "a binary"
in Elixir.
Both Elixir and Erlang allow for binary matching syntax. For a full reference refer to Elixir docs or Erlang docs accordingly. Here we're going to cover the differences:
Erlang
<<1, 2, 3>>
<<X:N,T/binary>>
<<X:4/little-signed-integer-unit:8>>
Elixir
<<1, 2, 3>>
<<x::size(n), t::binary>>
<<x::n, t::binary>>
<<x::little-signed-integer-size(4)-unit(8)>>
<<x::little-signed-integer-4*8>>
Elixir offers a literal syntax for creating a list of two-item tuples where the first item in the tuple is an atom and calls them keyword lists:
Erlang
Proplist = [{another_key, 20}, {key, 10}].
proplists:get_value(another_key, Proplist).
%=> 20
Elixir
kw = [another_key: 20, key: 10]
kw[:another_key]
#=> 20
Maps are a key-value store, with no ordering. Keys and values can be any term. Creating, updating and matching maps in both languages is shown below:
Erlang
Map = #{key => 0}.
Updated = Map#{key := 1}.
#{key := Value} = Updated.
Value =:= 1.
%=> true
Elixir
map = %{:key => 0}
map = %{map | :key => 1}
%{:key => value} = map
value === 1
#=> true
If the keys are all atoms, Elixir allows developers to use key: 0
for defining the map
as well as using .key
for accessing fields:
map = %{key: 0}
map = %{map | key: 1}
map.key === 1
Elixir supports a literal syntax for regular expressions. Such syntax allows regexes to be compiled at compilation time instead of runtime and does not require you to double escape special regex characters:
Erlang
{ ok, Pattern } = re:compile("abc\\s").
re:run("abc ", Pattern).
%=> { match, ["abc "] }
Elixir
Regex.run ~r/abc\s/, "abc "
#=> ["abc "]
Some operators are spelled differently. Some are not available in one of the languages and some erlang operators are functions in Elixir.
Erlang | Elixir | Meaning |
---|---|---|
and | NOT AVAILABLE | Logical 'and', evaluates both arguments |
andalso | and | Logical 'and', short-circuits |
or | NOT AVAILABLE | Logical 'or', evaluates both arguments |
orelse | or | Logical 'or', short-circuits |
NOT AVAILABLE | && | Logical 'and' using Elixir's notion of thruthiness |
NOT AVAILABLE | || | Logical 'or' using Elixir's notion of thruthiness |
=:= | === | A match operator |
=/= | !== | A negative match |
/= | != | Not equals |
=< | <= | Less than or equals |
rem | rem/2 function | remainder |
div | div/2 function | integer division |
Variables in Erlang can only be assigned once.
The Erlang shell provides a special command f
that allows you to erase the binding of a variable or all variables at once.
Elixir allows you to assign to a variable more than once.
If you want to match against the value of a previously assigned variable, you should use ^
:
Erlang
Eshell V5.9 (abort with ^G)
1> X = 10.
10
2> X = X + 1.
** exception error: no match of right hand side value 11
3> X1 = X + 1.
11
4> f(X).
ok
5> X = X1 * X1.
121
6> f().
ok
7> X.
* 1: variable 'X' is unbound
8> X1.
* 1: variable 'X1' is unbound
Elixir
iex> a = 1
1
iex> a = 2
2
iex> ^a = 3
** (MatchError) no match of right hand side value: 3
Invoking a function from a module uses different syntax. In Erlang, you would write
lists:last([1, 2]).
to invoke the last
function from the :lists
module. In Elixir, use the dot .
in place of the colon :
.
:lists.last([1, 2])
All of the Erlang built-ins reside in the :erlang
module.
Each Erlang module lives in its own file which has the following structure:
-module(hello_module).
-export([some_fun/0, some_fun/1]).
% A "Hello world" function
some_fun() ->
io:format('~s~n', ['Hello world!']).
% This one works only with lists
some_fun(List) when is_list(List) ->
io:format('~s~n', List).
% Non-exported functions are private
priv() ->
secret_info.
Here we create a module named hello_module
. In it we define three functions, the first two are made available for other modules to call via the export
directive at the top. It contains a list of functions, each of which is written in the format <function name>/<arity>
. Arity stands for the number of arguments.
An Elixir equivalent to the Erlang above:
defmodule HelloModule do
# A "Hello world" function
def some_fun do
IO.puts "Hello world!"
end
# This one works only with lists
def some_fun(list) when is_list(list) do
IO.inspect list
end
# A private function
defp priv do
:secret_info
end
end
In Elixir, it is also possible to have multiple modules in one file, as well as nested modules:
defmodule HelloModule do
defmodule Utils do
def util do
IO.puts "Utilize"
end
defp priv do
:cant_touch_this
end
end
def dummy do
:ok
end
end
defmodule ByeModule do
end
HelloModule.dummy
#=> :ok
HelloModule.Utils.util
#=> "Utilize"
HelloModule.Utils.priv
#=> ** (UndefinedFunctionError) undefined function: HelloModule.Utils.priv/0
Erlang's official documentation site has a nice collection of programming examples. It can be a good exercise to translate them into Elixir. Erlang cookbook offers even more useful code examples.
You can refer to the full Erlang crash course for additional differences in building modules, calling functions, etc.