UNDERSTANDING
ERLANG TERMS
SEATTLE ELIXIR MEETUP
DEC 2017
UNDERSTANDING ERLANG TERMS
MYTH
▸ Tail-recursive functions are much faster than body-
recursive functions
UNDERSTANDING ERLANG TERMS
HOW TO IMPLEMENT ERLANG’S TYPE SYSTEM?
▸ Dynamic typing
UNDERSTANDING ERLANG TERMS
INFORMATION = BITS + CONTEXT
+-----+-----+-----+-----+-----+-----+-----+-----+
|0x68 |0x69 |0x6c |0x6c |0x6f |0x00 |0x00 |0x00 |
+-----+-----+-----+-----+-----+-----+-----+-----+
|0x100|0x101|0x102|0x103|0x104|0x105|0x106|0x107|
+-----+-----+-----+-----+-----+-----+-----+-----+
+-----+-----+-----+-----+-----+-----+-----+-----+
| h | e | l | l | o | 0 | 0 | 0 |
+-----+-----+-----+-----+-----+-----+-----+-----+
|0x100|0x101|0x102|0x103|0x104|0x105|0x106|0x107|
+-----+-----+-----+-----+-----+-----+-----+-----+
+-----+-----+-----+-----+-----+-----+-----+-----+
| 26984 | 27756 | 111 | 0 |
+-----+-----+-----+-----+-----+-----+-----+-----+
|0x100|0x101|0x102|0x103|0x104|0x105|0x106|0x107|
+-----+-----+-----+-----+-----+-----+-----+-----+
+-----+-----+-----+-----+-----+-----+-----+-----+
| 1819044200 | 111 |
+-----+-----+-----+-----+-----+-----+-----+-----+
|0x100|0x101|0x102|0x103|0x104|0x105|0x106|0x107|
+-----+-----+-----+-----+-----+-----+-----+-----+
UNDERSTANDING ERLANG TERMS
ERLANG’S BUILDING BLOCK(PARTIALLY)
▸ Numbers
▸ 1, 2, 100
▸ 1.0, 3.14
▸ Atoms
▸ ok, true, false
▸ Tuples
▸ {}, {1, 2, 3}, {ok, 100}
▸ Lists
▸ [], [1, 2, 3]
▸ Maps
▸ #{name => “Jon Snow”, job => “King in the North”}
▸ Binaries
▸ <<“hello”>>, <<1, 2, 3>>
UNDERSTANDING ERLANG TERMS
A NAIVE IMPLEMENTATION
xxxxxxxx xxxxxxxx xxxxxxxx xxxxx000 integer
xxxxxxxx xxxxxxxx xxxxxxxx xxxxx001 float
xxxxxxxx xxxxxxxx xxxxxxxx xxxxx010 atom
xxxxxxxx xxxxxxxx xxxxxxxx xxxxx011 tuple
xxxxxxxx xxxxxxxx xxxxxxxx xxxxx100 list
xxxxxxxx xxxxxxxx xxxxxxxx xxxxx101 map
xxxxxxxx xxxxxxxx xxxxxxxx xxxxx110 binary
xxxxxxxx xxxxxxxx xxxxxxxx xxxxx111 *not in use*
UNDERSTANDING ERLANG TERMS
ERLANG TERM
/* erts/emulator/beam/sys.h */
typedef unsigned long Eterm erts_align_attribute(sizeof(long));
typedef unsigned long Uint erts_align_attribute(sizeof(long));
typedef Uint UWord;
/* erts/emulator/beam/erl_term.h */
typedef UWord Wterm;
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx 32-bits
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx 64-bits
int i = 100;
printf(“%p”, &i);
UNDERSTANDING ERLANG TERMS
DATA ALIGNMENT PROPERTY
+-----+-----+-----+-----+
| 100 |
+-----+-----+-----+-----+
|0x100|0x101|0x102|0x103|
+-----+-----+-----+-----+
+-----+-----+-----+-----+
| 100 |
+-----+-----+-----+-----+
|0x204|0x205|0x206|0x207|
+-----+-----+-----+-----+
+-----+-----+-----+-----+
| 100 |
+-----+-----+-----+-----+
|0x40c|0x40d|0x40e|0x40f|
+-----+-----+-----+-----+
0001 0000 0000
0010 0000 0100
0011 0000 1000
0100 0000 1100
+-----+-----+-----+-----+
| 100 |
+-----+-----+-----+-----+
|0x308|0x309|0x30a|0x30b|
+-----+-----+-----+-----+
UNDERSTANDING ERLANG TERMS
A STAGED TAG SCHEME FOR ERLANG
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx01 list
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx10 boxed
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 header
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx11 immediate 1
xxxxxxxx xxxxxxxx xxxxxxxx xxxx0011 pid
xxxxxxxx xxxxxxxx xxxxxxxx xxxx0111 port
xxxxxxxx xxxxxxxx xxxxxxxx xxxx1111 small int
xxxxxxxx xxxxxxxx xxxxxxxx xxxx1011 immediate 2
xxxxxxxx xxxxxxxx xxxxxxxx xx001011 atom
xxxxxxxx xxxxxxxx xxxxxxxx xx011011 catch
11111111 11111111 11111111 11111011 nil
UNDERSTANDING ERLANG TERMS
BOXED HEADER
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 header
xxxxxxxx xxxxxxxx xxxxxxxx xx000000 tuple
xxxxxxxx xxxxxxxx xxxxxxxx xx000100 binary match context
xxxxxxxx xxxxxxxx xxxxxxxx xx001000 pos big int
xxxxxxxx xxxxxxxx xxxxxxxx xx001100 neg big int
xxxxxxxx xxxxxxxx xxxxxxxx xx010000 reference
xxxxxxxx xxxxxxxx xxxxxxxx xx010100 function
xxxxxxxx xxxxxxxx xxxxxxxx xx011000 float
xxxxxxxx xxxxxxxx xxxxxxxx xx011100 export
xxxxxxxx xxxxxxxx xxxxxxxx xx100000 refc binary
xxxxxxxx xxxxxxxx xxxxxxxx xx100100 heap binary
xxxxxxxx xxxxxxxx xxxxxxxx xx101000 sub binary
xxxxxxxx xxxxxxxx xxxxxxxx xx101100 *not used
xxxxxxxx xxxxxxxx xxxxxxxx xx110000 external pid
xxxxxxxx xxxxxxxx xxxxxxxx xx110100 external port
xxxxxxxx xxxxxxxx xxxxxxxx xx111000 external reference
xxxxxxxx xxxxxxxx xxxxxxxx xx111100 map
UNDERSTANDING ERLANG TERMS
IMMEDIATE 1
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx11 immediate 1
xxxxxxxx xxxxxxxx xxxxxxxx xxxx1111 small int
xxxxxxxx xxxxxxxx xxxxxxxx xxxx0011 pid
xxxxxxxx xxxxxxxx xxxxxxxx xxxx0111 port
UNDERSTANDING ERLANG TERMS
IMMEDIATE 1
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx11 immediate 1
xxxxxxxx xxxxxxxx xxxxxxxx xxxx1111 small int
xxxxxxxx xxxxxxxx xxxxxxxx xxxx0011 pid
xxxxxxxx xxxxxxxx xxxxxxxx xxxx0111 port
UNDERSTANDING ERLANG TERMS
SMALL INT xxxxxxxx xxxxxxxx xxxxxxxx xxxx1111
xxxxxxxx xxxxxxxx xxxxxxxx xxxx1111 32-bits
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxx1111 64-bits
01111111 11111111 11111111 11111111 TMAX 32
10000000 00000000 00000000 00001111 TMIN 32
-134,217,728 - 134,217,727
01111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 TMAX 64
10000000 00000000 00000000 00000000 00000000 00000000 00000000 00001111 TMIN 64
-576,460,752,303,423,488 - 576,460,752,303,423,487
UNDERSTANDING ERLANG TERMS
IMMEDIATE 1
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx11 immediate 1
xxxxxxxx xxxxxxxx xxxxxxxx xxxx1111 small int
xxxxxxxx xxxxxxxx xxxxxxxx xxxx0011 pid
xxxxxxxx xxxxxxxx xxxxxxxx xxxx0111 port
UNDERSTANDING ERLANG TERMS
PID
▸ Default 2^18 processes(262,144)
▸ Min 1024
▸ Max 2^27 - 1 = 134,217,727, same as TMAX 32
xxxxxxxx xxxxxxxx xxxxxxxx xxxx0011
<0.157.0>

00000000 00000000 00000100 11101000 00000000 00000000 00001001 11010011
<0.4520.2>

00000000 00000000 00000101 01000001 00000000 00010001 00011010 10000011
% iex --erl "+P 1024" -S mix
Interactive Elixir (1.5.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> :erlang.system_info(:process_limit)
1024
UNDERSTANDING ERLANG TERMS
IMMEDIATE 1
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx11 immediate 1
xxxxxxxx xxxxxxxx xxxxxxxx xxxx1111 small int
xxxxxxxx xxxxxxxx xxxxxxxx xxxx0011 pid
xxxxxxxx xxxxxxxx xxxxxxxx xxxx0111 port
UNDERSTANDING ERLANG TERMS
PORT
▸ Default 2^16 ports (65536)
▸ Max 2^27 - 1 = 134,217,727, same as TMAX 32
xxxxxxxx xxxxxxxx xxxxxxxx xxxx0111
UNDERSTANDING ERLANG TERMS
IMMEDIATE 2
xxxxxxxx xxxxxxxx xxxxxxxx xxxx1011 immediate 2
xxxxxxxx xxxxxxxx xxxxxxxx xx001011 atom
xxxxxxxx xxxxxxxx xxxxxxxx xx011011 catch
11111111 11111111 11111111 11111011 nil
UNDERSTANDING ERLANG TERMS
IMMEDIATE 2
xxxxxxxx xxxxxxxx xxxxxxxx xxxx1011 immediate 2
xxxxxxxx xxxxxxxx xxxxxxxx xx001011 atom
xxxxxxxx xxxxxxxx xxxxxxxx xx011011 catch
11111111 11111111 11111111 11111011 nil
UNDERSTANDING ERLANG TERMS
ATOM
▸ Default 2^20 = 1,048,576
▸ Min 8192
▸ Max 67108864 on 32-bits
▸ Max 2147483647 on 64-bits
xxxxxxxx xxxxxxxx xxxxxxxx xx001011
xxxxxxxx xxxxxxxx xxxxxxxx xx001011 32-bits
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xx001011 64-bits
11111111 11111111 11111111 11001011 MAX 32
67,108,863
64MB
00000000 00000000 00000000 00011111 11111111 11111111 11111111 11001011 MAX 64
2,147,483,647
2GB
UNDERSTANDING ERLANG TERMS
IMMEDIATE 2
xxxxxxxx xxxxxxxx xxxxxxxx xxxx1011 immediate 2
xxxxxxxx xxxxxxxx xxxxxxxx xx001011 atom
xxxxxxxx xxxxxxxx xxxxxxxx xx011011 catch
11111111 11111111 11111111 11111011 nil
UNDERSTANDING ERLANG TERMS
CATCH
▸ Stores the address of catch block
xxxxxxxx xxxxxxxx xxxxxxxx xx011011
UNDERSTANDING ERLANG TERMS
IMMEDIATE 2
xxxxxxxx xxxxxxxx xxxxxxxx xxxx1011 immediate 2
xxxxxxxx xxxxxxxx xxxxxxxx xx001011 atom
xxxxxxxx xxxxxxxx xxxxxxxx xx011011 catch
11111111 11111111 11111111 11111011 nil
UNDERSTANDING ERLANG TERMS
NIL
▸ []
▸ Not nil in Elixir
11111111 11111111 11111111 11011011
11111111 11111111 11111111 11001011 32-bits
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11001011 64-bits
UNDERSTANDING ERLANG TERMS
PRIMARY TAG
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx01 list
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx10 boxed
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 header
UNDERSTANDING ERLANG TERMS
PRIMARY TAG
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx01 list
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx10 boxed
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 header
UNDERSTANDING ERLANG TERMS
LIST(CONS)
▸ car
▸ cdr
▸ [car | cdr]
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx01
[1]
0x100 0x000000000000001f car: 1
0x108 0xfffffffffffffffb cdr: []
0x100 00000000 00000000 00000001 00000000
0x101 00000000 00000000 00000001 00000001
[1, 2]
0x200 0x000000000000002f car: 2
0x208 0xfffffffffffffffb cdr: []
0x210 0x000000000000001f car: 1
0x218 0x0000000000000201 cdr: [2]
0x210 00000000 00000000 00000011 00010000
0x211 00000000 00000000 00000011 00010001
[1 | 2]
0x300 0x000000000000001f car: 1
0x308 0x000000000000002f cdr: 2
0x300 00000000 00000000 00000011 00000000
0x301 00000000 00000000 00000011 00000001
UNDERSTANDING ERLANG TERMS
PRIMARY TAG
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx01 list
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx10 boxed
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 header
UNDERSTANDING ERLANG TERMS
BOXED xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx10
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx10
UNDERSTANDING ERLANG TERMS
BOXED HEADER
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 header
xxxxxxxx xxxxxxxx xxxxxxxx xx000000 tuple
xxxxxxxx xxxxxxxx xxxxxxxx xx000100 binary match context
xxxxxxxx xxxxxxxx xxxxxxxx xx001000 pos big int
xxxxxxxx xxxxxxxx xxxxxxxx xx001100 neg big int
xxxxxxxx xxxxxxxx xxxxxxxx xx010000 reference
xxxxxxxx xxxxxxxx xxxxxxxx xx010100 function
xxxxxxxx xxxxxxxx xxxxxxxx xx011000 float
xxxxxxxx xxxxxxxx xxxxxxxx xx011100 export
xxxxxxxx xxxxxxxx xxxxxxxx xx100000 refc binary
xxxxxxxx xxxxxxxx xxxxxxxx xx100100 heap binary
xxxxxxxx xxxxxxxx xxxxxxxx xx101000 sub binary
xxxxxxxx xxxxxxxx xxxxxxxx xx101100 *not used
xxxxxxxx xxxxxxxx xxxxxxxx xx110000 external pid
xxxxxxxx xxxxxxxx xxxxxxxx xx110100 external port
xxxxxxxx xxxxxxxx xxxxxxxx xx111000 external reference
xxxxxxxx xxxxxxxx xxxxxxxx xx111100 map
UNDERSTANDING ERLANG TERMS
BOXED HEADER
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 header
xxxxxxxx xxxxxxxx xxxxxxxx xx000000 tuple
xxxxxxxx xxxxxxxx xxxxxxxx xx000100 binary match context
xxxxxxxx xxxxxxxx xxxxxxxx xx001000 pos big int
xxxxxxxx xxxxxxxx xxxxxxxx xx001100 neg big int
xxxxxxxx xxxxxxxx xxxxxxxx xx010000 reference
xxxxxxxx xxxxxxxx xxxxxxxx xx010100 function
xxxxxxxx xxxxxxxx xxxxxxxx xx011000 float
xxxxxxxx xxxxxxxx xxxxxxxx xx011100 export
xxxxxxxx xxxxxxxx xxxxxxxx xx100000 refc binary
xxxxxxxx xxxxxxxx xxxxxxxx xx100100 heap binary
xxxxxxxx xxxxxxxx xxxxxxxx xx101000 sub binary
xxxxxxxx xxxxxxxx xxxxxxxx xx101100 *not used
xxxxxxxx xxxxxxxx xxxxxxxx xx110000 external pid
xxxxxxxx xxxxxxxx xxxxxxxx xx110100 external port
xxxxxxxx xxxxxxxx xxxxxxxx xx111000 external reference
xxxxxxxx xxxxxxxx xxxxxxxx xx111100 map
UNDERSTANDING ERLANG TERMS
TUPLE xxxxxxxx xxxxxxxx xxxxxxxx xx000000
{}
0x100 0x0000000000000000 Arity(0) … 0000 0000
0x100 00000000 00000000 00000001 00000000
0x102 00000000 00000000 00000001 00000010
{1}
0x200 0x0000000000000040 Arity(1) … 0100 0000
0x208 0x000000000000001f 1
0x200 00000000 00000000 00000010 00000000
0x202 00000000 00000000 00000010 00000010
{1, 2}
0x300 0x0000000000000080 Arity(2) … 1000 0000
0x308 0x000000000000001f 1
0x310 0x000000000000002f 2
0x300 00000000 00000000 00000011 00000000
0x302 00000000 00000000 00000011 00000010
UNDERSTANDING ERLANG TERMS
BOXED HEADER
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 header
xxxxxxxx xxxxxxxx xxxxxxxx xx000000 tuple
xxxxxxxx xxxxxxxx xxxxxxxx xx000100 binary match context
xxxxxxxx xxxxxxxx xxxxxxxx xx001000 pos big int
xxxxxxxx xxxxxxxx xxxxxxxx xx001100 neg big int
xxxxxxxx xxxxxxxx xxxxxxxx xx010000 reference
xxxxxxxx xxxxxxxx xxxxxxxx xx010100 function
xxxxxxxx xxxxxxxx xxxxxxxx xx011000 float
xxxxxxxx xxxxxxxx xxxxxxxx xx011100 export
xxxxxxxx xxxxxxxx xxxxxxxx xx100000 refc binary
xxxxxxxx xxxxxxxx xxxxxxxx xx100100 heap binary
xxxxxxxx xxxxxxxx xxxxxxxx xx101000 sub binary
xxxxxxxx xxxxxxxx xxxxxxxx xx101100 *not used
xxxxxxxx xxxxxxxx xxxxxxxx xx110000 external pid
xxxxxxxx xxxxxxxx xxxxxxxx xx110100 external port
xxxxxxxx xxxxxxxx xxxxxxxx xx111000 external reference
xxxxxxxx xxxxxxxx xxxxxxxx xx111100 map
UNDERSTANDING ERLANG TERMS
BIG INT xxxxxxxx xxxxxxxx xxxxxxxx xx001x00
(1 <<< 59) - 1
01111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111 MAX small int
(1 <<< 59)
00000000_00000000_00000000_00000000_10000110_10010011_10001000_00101010 boxed
00000000_00000000_00000000_00000000_00000000_00000000_00000000_01001000 pos bignum
00001000_00000000_00000000_00000000_00000000_00000000_00000000_00000000
(1 <<< 59) + 1
00000000_00000000_00000000_00000000_10000110_10010011_10001000_00101010 boxed
00000000_00000000_00000000_00000000_00000000_00000000_00000000_01001000 pos bignum
00001000_00000000_00000000_00000000_00000000_00000000_00000000_00000001
(-1 <<< 59) - 1
00000000_00000000_00000000_00000000_10000110_10010011_10001000_00101010 boxed
00000000_00000000_00000000_00000000_00000000_00000000_00000000_01001100 neg bignum
00001000_00000000_00000000_00000000_00000000_00000000_00000000_00000001
(-1 <<< 59)
10000000_00000000_00000000_00000000_00000000_00000000_00000000_00001111 MIN small int
UNDERSTANDING ERLANG TERMS
BOXED HEADER
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 header
xxxxxxxx xxxxxxxx xxxxxxxx xx000000 tuple
xxxxxxxx xxxxxxxx xxxxxxxx xx000100 binary match context
xxxxxxxx xxxxxxxx xxxxxxxx xx001000 pos big int
xxxxxxxx xxxxxxxx xxxxxxxx xx001100 neg big int
xxxxxxxx xxxxxxxx xxxxxxxx xx010000 reference
xxxxxxxx xxxxxxxx xxxxxxxx xx010100 function
xxxxxxxx xxxxxxxx xxxxxxxx xx011000 float
xxxxxxxx xxxxxxxx xxxxxxxx xx011100 export
xxxxxxxx xxxxxxxx xxxxxxxx xx100000 refc binary
xxxxxxxx xxxxxxxx xxxxxxxx xx100100 heap binary
xxxxxxxx xxxxxxxx xxxxxxxx xx101000 sub binary
xxxxxxxx xxxxxxxx xxxxxxxx xx101100 *not used
xxxxxxxx xxxxxxxx xxxxxxxx xx110000 external pid
xxxxxxxx xxxxxxxx xxxxxxxx xx110100 external port
xxxxxxxx xxxxxxxx xxxxxxxx xx111000 external reference
xxxxxxxx xxxxxxxx xxxxxxxx xx111100 map
UNDERSTANDING ERLANG TERMS
FLOAT
▸ IEEE754
xxxxxxxx xxxxxxxx xxxxxxxx xx011000
0.0
00000000_00000000_00000000_00000000_10000110_10010011_10001000_00101010 boxed
00000000_00000000_00000000_00000000_00000000_00000000_00000000_01011000 float
00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000
1.0
00000000_00000000_00000000_00000000_10000110_10010011_10001000_00101010 boxed
00000000_00000000_00000000_00000000_00000000_00000000_00000000_01011000 float
00111111_11110000_00000000_00000000_00000000_00000000_00000000_00000000
-1.0
00000000_00000000_00000000_00000000_10000110_10010011_10001000_00101010 boxed
00000000_00000000_00000000_00000000_00000000_00000000_00000000_01011000 float
10111111_11110000_00000000_00000000_00000000_00000000_00000000_00000000
UNDERSTANDING ERLANG TERMS
BOXED HEADER
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 header
xxxxxxxx xxxxxxxx xxxxxxxx xx000000 tuple
xxxxxxxx xxxxxxxx xxxxxxxx xx000100 binary match context
xxxxxxxx xxxxxxxx xxxxxxxx xx001000 pos big int
xxxxxxxx xxxxxxxx xxxxxxxx xx001100 neg big int
xxxxxxxx xxxxxxxx xxxxxxxx xx010000 reference
xxxxxxxx xxxxxxxx xxxxxxxx xx010100 function
xxxxxxxx xxxxxxxx xxxxxxxx xx011000 float
xxxxxxxx xxxxxxxx xxxxxxxx xx011100 export
xxxxxxxx xxxxxxxx xxxxxxxx xx100000 refc binary
xxxxxxxx xxxxxxxx xxxxxxxx xx100100 heap binary
xxxxxxxx xxxxxxxx xxxxxxxx xx101000 sub binary
xxxxxxxx xxxxxxxx xxxxxxxx xx101100 *not used
xxxxxxxx xxxxxxxx xxxxxxxx xx110000 external pid
xxxxxxxx xxxxxxxx xxxxxxxx xx110100 external port
xxxxxxxx xxxxxxxx xxxxxxxx xx111000 external reference
xxxxxxxx xxxxxxxx xxxxxxxx xx111100 map
UNDERSTANDING ERLANG TERMS
HEAP BINARY xxxxxxxx xxxxxxxx xxxxxxxx xx100100
<<>>
00000000_00000000_00000000_00000000_10000110_10010011_10001000_00101010 boxed
00000000_00000000_00000000_00000000_00000000_00000000_00000000_01100100 heap binary
00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000
“hello”
00000000_00000000_00000000_00000000_10000110_10010011_10001000_00101010 boxed
00000000_00000000_00000000_00000000_00000000_00000000_00000000_10100100 heap binary
00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000101 size(5)
00000000_00000000_00000000_01101111_01101100_01101100_01100101_01101000
o l l e h
“hello world!”
00000000_00000000_00000000_00000000_10000110_10010011_10001000_00101010 boxed
00000000_00000000_00000000_00000000_00000000_00000000_00000000_11100100 heap binary
00000000_00000000_00000000_00000000_00000000_00000000_00000000_00001100 size(12)
01101111_01110111_00100000_01101111_01101100_01101100_01100101_01101000
o w s o l l e h
00000000_00000000_00000000_00000000_00100001_01100100_01101100_01110010
! d l r
UNDERSTANDING ERLANG TERMS
MYTH WALKTHROUGH
▸ Tail-recursive functions are much faster than body-
recursive functions
UNDERSTANDING ERLANG TERMS
TAIL-RECURSIVE VS BODY-RECURSIVE
defmodule Foo do
def add1_tail(list) do
do_add1_tail(list, [])
end
defp do_add1_tail([], acc) do
Enum.reverse(acc)
end
defp do_add1_tail([h | t], acc) do
do_add1_tail(t, [h + 1 | acc])
end
def add1_body([]) do
[]
end
def add1_body([h | t]) do
[h + 1 | add1_body(t)]
end
end
UNDERSTANDING ERLANG TERMS
TAIL-RECURSIVE
| BEAM STACK |
| Address | Contents |
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1af8 | 0x0000000042fcae49 | [1,2,3,4,5]
| 0x0000000015ac1af0 | 0x0000000019ede830 | BEAM PC 'Elixir.Foo':run1/0 + 0x5
|--------------------|--------------------|
|--------------------|--------------------|
|--------------------|--------------------|
| Address | Contents |
| H E A P |
defmodule Foo do
def run1 do
add1_tail([1, 2, 3, 4, 5])
end
def add1_tail(list) do
do_add1_tail(list, [])
end
defp do_add1_tail([], acc) do
Enum.reverse(acc)
end
defp do_add1_tail([h | t], acc) do
do_add1_tail(t, [h + 1 | acc])
end
end
UNDERSTANDING ERLANG TERMS
TAIL-RECURSIVE
| BEAM STACK |
| Address | Contents |
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1af8 | 0x0000000042fcae59 | [2,3,4,5]
| 0x0000000015ac1af0 | 0xfffffffffffffffb | []
| 0x0000000015ac1ae8 | 0x000000000000001f | 1
| 0x0000000015ac1ae0 | 0x0000000019ede830 | BEAM PC 'Elixir.Foo':run1/0 + 0x5
|--------------------|--------------------|
|--------------------|--------------------|
|--------------------|--------------------|
| Address | Contents |
| H E A P |
defmodule Foo do
def run1 do
add1_tail([1, 2, 3, 4, 5])
end
def add1_tail(list) do
do_add1_tail(list, [])
end
defp do_add1_tail([], acc) do
Enum.reverse(acc)
end
defp do_add1_tail([h | t], acc) do
do_add1_tail(t, [h + 1 | acc])
end
end
UNDERSTANDING ERLANG TERMS
TAIL-RECURSIVE
| BEAM STACK |
| Address | Contents |
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1af8 | 0x0000000042fcae69 | [3,4,5]
| 0x0000000015ac1af0 | 0x0000000015ac13c9 | [2]
| 0x0000000015ac1ae8 | 0x000000000000002f | 2
| 0x0000000015ac1ae0 | 0x0000000019ede830 | BEAM PC 'Elixir.Foo':run1/0 + 0x5
|--------------------|--------------------|
|--------------------|--------------------|
| 0x0000000015ac13d0 | 0xfffffffffffffffb | []
| 0x0000000015ac13c8 | 0x000000000000002f | 2
|--------------------|--------------------|
| Address | Contents |
| H E A P |
defmodule Foo do
def run1 do
add1_tail([1, 2, 3, 4, 5])
end
def add1_tail(list) do
do_add1_tail(list, [])
end
defp do_add1_tail([], acc) do
Enum.reverse(acc)
end
defp do_add1_tail([h | t], acc) do
do_add1_tail(t, [h + 1 | acc])
end
end
UNDERSTANDING ERLANG TERMS
TAIL-RECURSIVE
| BEAM STACK |
| Address | Contents |
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1af8 | 0x0000000042fcae79 | [4,5]
| 0x0000000015ac1af0 | 0x0000000015ac13d9 | [3,2]
| 0x0000000015ac1ae8 | 0x000000000000003f | 3
| 0x0000000015ac1ae0 | 0x0000000019ede830 | BEAM PC 'Elixir.Foo':run1/0 + 0x5
|--------------------|--------------------|
|--------------------|--------------------|
| 0x0000000015ac13e0 | 0x0000000015ac13c9 | [2]
| 0x0000000015ac13d8 | 0x000000000000003f | 3
| 0x0000000015ac13d0 | 0xfffffffffffffffb | []
| 0x0000000015ac13c8 | 0x000000000000002f | 2
|--------------------|--------------------|
| Address | Contents |
| H E A P |
defmodule Foo do
def run1 do
add1_tail([1, 2, 3, 4, 5])
end
def add1_tail(list) do
do_add1_tail(list, [])
end
defp do_add1_tail([], acc) do
Enum.reverse(acc)
end
defp do_add1_tail([h | t], acc) do
do_add1_tail(t, [h + 1 | acc])
end
end
UNDERSTANDING ERLANG TERMS
TAIL-RECURSIVE
| BEAM STACK |
| Address | Contents |
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1af8 | 0x0000000042fcae89 | [5]
| 0x0000000015ac1af0 | 0x0000000015ac13e9 | [4,3,2]
| 0x0000000015ac1ae8 | 0x000000000000004f | 4
| 0x0000000015ac1ae0 | 0x0000000019ede830 | BEAM PC 'Elixir.Foo':run1/0 + 0x5
|--------------------|--------------------|
|--------------------|--------------------|
| 0x0000000015ac13f0 | 0x0000000015ac13d9 | [3,2]
| 0x0000000015ac13e8 | 0x000000000000004f | 4
| 0x0000000015ac13e0 | 0x0000000015ac13c9 | [2]
| 0x0000000015ac13d8 | 0x000000000000003f | 3
| 0x0000000015ac13d0 | 0xfffffffffffffffb | []
| 0x0000000015ac13c8 | 0x000000000000002f | 2
|--------------------|--------------------|
| Address | Contents |
| H E A P |
defmodule Foo do
def run1 do
add1_tail([1, 2, 3, 4, 5])
end
def add1_tail(list) do
do_add1_tail(list, [])
end
defp do_add1_tail([], acc) do
Enum.reverse(acc)
end
defp do_add1_tail([h | t], acc) do
do_add1_tail(t, [h + 1 | acc])
end
end
UNDERSTANDING ERLANG TERMS
TAIL-RECURSIVE
| BEAM STACK |
| Address | Contents |
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1af8 | 0xfffffffffffffffb | []
| 0x0000000015ac1af0 | 0x0000000015ac13f9 | [5,4,3,2]
| 0x0000000015ac1ae8 | 0x000000000000005f | 5
| 0x0000000015ac1ae0 | 0x0000000019ede830 | BEAM PC 'Elixir.Foo':run1/0 + 0x5
|--------------------|--------------------|
|--------------------|--------------------|
| 0x0000000015ac1400 | 0x0000000015ac13e9 | [4,3,2]
| 0x0000000015ac13f8 | 0x000000000000005f | 5
| 0x0000000015ac13f0 | 0x0000000015ac13d9 | [3,2]
| 0x0000000015ac13e8 | 0x000000000000004f | 4
| 0x0000000015ac13e0 | 0x0000000015ac13c9 | [2]
| 0x0000000015ac13d8 | 0x000000000000003f | 3
| 0x0000000015ac13d0 | 0xfffffffffffffffb | []
| 0x0000000015ac13c8 | 0x000000000000002f | 2
|--------------------|--------------------|
| Address | Contents |
| H E A P |
defmodule Foo do
def run1 do
add1_tail([1, 2, 3, 4, 5])
end
def add1_tail(list) do
do_add1_tail(list, [])
end
defp do_add1_tail([], acc) do
Enum.reverse(acc)
end
defp do_add1_tail([h | t], acc) do
do_add1_tail(t, [h + 1 | acc])
end
end
UNDERSTANDING ERLANG TERMS
TAIL-RECURSIVE
| BEAM STACK |
| Address | Contents |
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1af8 | 0x0000000015ac1409 | [6,5,4,3,2]
| 0x0000000015ac1af0 | 0x0000000019ede830 | BEAM PC 'Elixir.Foo':run1/0 + 0x5
|--------------------|--------------------|
|--------------------|--------------------|
| 0x0000000015ac1410 | 0x0000000015ac13f9 | [5,4,3,2]
| 0x0000000015ac1408 | 0x000000000000006f | 6
| 0x0000000015ac1400 | 0x0000000015ac13e9 | [4,3,2]
| 0x0000000015ac13f8 | 0x000000000000005f | 5
| 0x0000000015ac13f0 | 0x0000000015ac13d9 | [3,2]
| 0x0000000015ac13e8 | 0x000000000000004f | 4
| 0x0000000015ac13e0 | 0x0000000015ac13c9 | [2]
| 0x0000000015ac13d8 | 0x000000000000003f | 3
| 0x0000000015ac13d0 | 0xfffffffffffffffb | []
| 0x0000000015ac13c8 | 0x000000000000002f | 2
|--------------------|--------------------|
| Address | Contents |
| H E A P |
defmodule Foo do
def run1 do
add1_tail([1, 2, 3, 4, 5])
end
def add1_tail(list) do
do_add1_tail(list, [])
end
defp do_add1_tail([], acc) do
Enum.reverse(acc)
end
defp do_add1_tail([h | t], acc) do
do_add1_tail(t, [h + 1 | acc])
end
end
UNDERSTANDING ERLANG TERMS
TAIL-RECURSIVE
| BEAM STACK |
| Address | Contents |
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1b08 | 0x0000000015ac1459 | [2,3,4,5,6]
| 0x0000000015ac1b00 | 0x000000001525a148 | BEAM PC normal-process-exit
|--------------------|--------------------|
|--------------------|--------------------|
| 0x0000000015ac1460 | 0x0000000015ac1449 | [3,4,5,6]
| 0x0000000015ac1458 | 0x000000000000002f | 2
| 0x0000000015ac1450 | 0x0000000015ac1439 | [4,5,6]
| 0x0000000015ac1448 | 0x000000000000003f | 3
| 0x0000000015ac1440 | 0x0000000015ac1429 | [5,6]
| 0x0000000015ac1438 | 0x000000000000004f | 4
| 0x0000000015ac1430 | 0x0000000015ac1419 | [6]
| 0x0000000015ac1428 | 0x000000000000005f | 5
| 0x0000000015ac1420 | 0xfffffffffffffffb | []
| 0x0000000015ac1418 | 0x000000000000006f | 6
| 0x0000000015ac1410 | 0x0000000015ac13f9 | [5,4,3,2]
| 0x0000000015ac1408 | 0x000000000000006f | 6
| 0x0000000015ac1400 | 0x0000000015ac13e9 | [4,3,2]
| 0x0000000015ac13f8 | 0x000000000000005f | 5
| 0x0000000015ac13f0 | 0x0000000015ac13d9 | [3,2]
| 0x0000000015ac13e8 | 0x000000000000004f | 4
| 0x0000000015ac13e0 | 0x0000000015ac13c9 | [2]
| 0x0000000015ac13d8 | 0x000000000000003f | 3
| 0x0000000015ac13d0 | 0xfffffffffffffffb | []
| 0x0000000015ac13c8 | 0x000000000000002f | 2
|--------------------|--------------------|
| Address | Contents |
| H E A P |
defmodule Foo do
def run1 do
add1_tail([1, 2, 3, 4, 5])
end
def add1_tail(list) do
do_add1_tail(list, [])
end
defp do_add1_tail([], acc) do
Enum.reverse(acc)
end
defp do_add1_tail([h | t], acc) do
do_add1_tail(t, [h + 1 | acc])
end
end
UNDERSTANDING ERLANG TERMS
BODY-RECURSIVE
| BEAM STACK |
| Address | Contents |
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1af8 | 0x0000000042fcae59 | [2,3,4,5]
| 0x0000000015ac1af0 | 0x000000000000001f | 1
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1ae8 | 0x0000000019ede8b0 | BEAM PC 'Elixir.Foo':run2/0 + 0x5
|--------------------|--------------------|
|--------------------|--------------------|
|--------------------|--------------------|
| Address | Contents |
| H E A P |
defmodule Foo do
def run2 do
add1_body([1, 2, 3, 4, 5])
end
def add1_body([]) do
[]
end
def add1_body([h | t]) do
[h + 1 | add1_body(t)]
end
end
UNDERSTANDING ERLANG TERMS
BODY-RECURSIVE
| BEAM STACK |
| Address | Contents |
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1af8 | 0x000000000000002f | 2
| 0x0000000015ac1af0 | 0x0000000019ede8b0 | BEAM PC 'Elixir.Foo':run2/0 + 0x5
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1ae8 | 0x0000000042fcae69 | [3,4,5]
| 0x0000000015ac1ae0 | 0x000000000000002f | 2
| 0x0000000015ac1ad8 | 0x0000000019ede000 | BEAM PC ‘Elixir.Foo':add1_body/1 + 0x12
|--------------------|--------------------|
|--------------------|--------------------|
|--------------------|--------------------|
| Address | Contents |
| H E A P |
defmodule Foo do
def run2 do
add1_body([1, 2, 3, 4, 5])
end
def add1_body([]) do
[]
end
def add1_body([h | t]) do
[h + 1 | add1_body(t)]
end
end
UNDERSTANDING ERLANG TERMS
BODY-RECURSIVE
| BEAM STACK |
| Address | Contents |
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1af8 | 0x000000000000002f | 2
| 0x0000000015ac1af0 | 0x0000000019ede8b0 | BEAM PC 'Elixir.Foo':run2/0 + 0x5
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1ae8 | 0x000000000000003f | 3
| 0x0000000015ac1ae0 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1ad8 | 0x0000000042fcae79 | [4,5]
| 0x0000000015ac1ad0 | 0x000000000000003f | 3
| 0x0000000015ac1ac8 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12
|--------------------|--------------------|
|--------------------|--------------------|
|--------------------|--------------------|
| Address | Contents |
| H E A P |
defmodule Foo do
def run2 do
add1_body([1, 2, 3, 4, 5])
end
def add1_body([]) do
[]
end
def add1_body([h | t]) do
[h + 1 | add1_body(t)]
end
end
UNDERSTANDING ERLANG TERMS
BODY-RECURSIVE
| BEAM STACK |
| Address | Contents |
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1af8 | 0x000000000000002f | 2
| 0x0000000015ac1af0 | 0x0000000019ede8b0 | BEAM PC 'Elixir.Foo':run2/0 + 0x5
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1ae8 | 0x000000000000003f | 3
| 0x0000000015ac1ae0 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1ad8 | 0x000000000000004f | 4
| 0x0000000015ac1ad0 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1ac8 | 0x0000000042fcae89 | [5]
| 0x0000000015ac1ac0 | 0x000000000000004f | 4
| 0x0000000015ac1ab8 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12
|--------------------|--------------------|
|--------------------|--------------------|
|--------------------|--------------------|
| Address | Contents |
| H E A P |
defmodule Foo do
def run2 do
add1_body([1, 2, 3, 4, 5])
end
def add1_body([]) do
[]
end
def add1_body([h | t]) do
[h + 1 | add1_body(t)]
end
end
UNDERSTANDING ERLANG TERMS
BODY-RECURSIVE
| BEAM STACK |
| Address | Contents |
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1af8 | 0x000000000000002f | 2
| 0x0000000015ac1af0 | 0x0000000019ede8b0 | BEAM PC 'Elixir.Foo':run2/0 + 0x5
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1ae8 | 0x000000000000003f | 3
| 0x0000000015ac1ae0 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1ad8 | 0x000000000000004f | 4
| 0x0000000015ac1ad0 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1ac8 | 0x000000000000005f | 5
| 0x0000000015ac1ac0 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1ab8 | 0xfffffffffffffffb | []
| 0x0000000015ac1ab0 | 0x000000000000005f | 5
| 0x0000000015ac1aa8 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12
|--------------------|--------------------|
|--------------------|--------------------|
|--------------------|--------------------|
| Address | Contents |
| H E A P |
defmodule Foo do
def run2 do
add1_body([1, 2, 3, 4, 5])
end
def add1_body([]) do
[]
end
def add1_body([h | t]) do
[h + 1 | add1_body(t)]
end
end
UNDERSTANDING ERLANG TERMS
BODY-RECURSIVE
| BEAM STACK |
| Address | Contents |
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1af8 | 0x000000000000002f | 2
| 0x0000000015ac1af0 | 0x0000000019ede8b0 | BEAM PC 'Elixir.Foo':run2/0 + 0x5
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1ae8 | 0x000000000000003f | 3
| 0x0000000015ac1ae0 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1ad8 | 0x000000000000004f | 4
| 0x0000000015ac1ad0 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1ac8 | 0x000000000000005f | 5
| 0x0000000015ac1ac0 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1ab8 | 0x000000000000006f | 6
| 0x0000000015ac1ab0 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1aa8 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12
|--------------------|--------------------|
|--------------------|--------------------|
|--------------------|--------------------|
| Address | Contents |
| H E A P |
defmodule Foo do
def run2 do
add1_body([1, 2, 3, 4, 5])
end
def add1_body([]) do
[]
end
def add1_body([h | t]) do
[h + 1 | add1_body(t)]
end
end
UNDERSTANDING ERLANG TERMS
BODY-RECURSIVE
| BEAM STACK |
| Address | Contents |
|--------------------|--------------------| BEAM ACTIVATION RECORD
| 0x0000000015ac1b08 | 0x0000000015ac1409 | [2,3,4,5,6]
| 0x0000000015ac1b00 | 0x000000001525a148 | BEAM PC normal-process-exit
|--------------------|--------------------|
|--------------------|--------------------|
| 0x0000000015ac1410 | 0x0000000015ac13f9 | [3,4,5,6]
| 0x0000000015ac1408 | 0x000000000000002f | 2
| 0x0000000015ac1400 | 0x0000000015ac13e9 | [4,5,6]
| 0x0000000015ac13f8 | 0x000000000000003f | 3
| 0x0000000015ac13f0 | 0x0000000015ac13d9 | [5,6]
| 0x0000000015ac13e8 | 0x000000000000004f | 4
| 0x0000000015ac13e0 | 0x0000000015ac13c9 | [6]
| 0x0000000015ac13d8 | 0x000000000000005f | 5
| 0x0000000015ac13d0 | 0xfffffffffffffffb | []
| 0x0000000015ac13c8 | 0x000000000000006f | 6
|--------------------|--------------------|
| Address | Contents |
| H E A P |
defmodule Foo do
def run2 do
add1_body([1, 2, 3, 4, 5])
end
def add1_body([]) do
[]
end
def add1_body([h | t]) do
[h + 1 | add1_body(t)]
end
end
UNDERSTANDING ERLANG TERMS
MYTH DEMYSTIFY
▸ Use the version that makes your code cleaner (hint: it is
usually the body-recursive version)
▸ A tail-recursive function that does not need to reverse the
list at the end is faster than a body-recursive function
UNDERSTANDING ERLANG TERMS
RESOURCES
▸ The Seven Myths of Erlang Performance
▸ http://erlang.org/doc/efficiency_guide/myths.html
▸ A Staged Tag Scheme for Erlang(2000)
▸ http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.142.2827
▸ The Erlang Type System and Tags(The BEAM Book)
▸ https://happi.github.io/theBeamBook/#CH-TypeSystem
▸ Data Types Memory Layout(BEAM-WISDOM)
▸ http://beam-wisdoms.clau.se/en/latest/indepth-memory-layout.html
▸ Erlang/OTP source code
▸ https://github.com/erlang/otp/blob/master/erts/emulator/beam/erl_term.h
▸ ETerm library
▸ https://github.com/sunboshan/eterm

Understanding Erlang Terms

  • 1.
  • 2.
    UNDERSTANDING ERLANG TERMS MYTH ▸Tail-recursive functions are much faster than body- recursive functions
  • 3.
    UNDERSTANDING ERLANG TERMS HOWTO IMPLEMENT ERLANG’S TYPE SYSTEM? ▸ Dynamic typing
  • 4.
    UNDERSTANDING ERLANG TERMS INFORMATION= BITS + CONTEXT +-----+-----+-----+-----+-----+-----+-----+-----+ |0x68 |0x69 |0x6c |0x6c |0x6f |0x00 |0x00 |0x00 | +-----+-----+-----+-----+-----+-----+-----+-----+ |0x100|0x101|0x102|0x103|0x104|0x105|0x106|0x107| +-----+-----+-----+-----+-----+-----+-----+-----+ +-----+-----+-----+-----+-----+-----+-----+-----+ | h | e | l | l | o | 0 | 0 | 0 | +-----+-----+-----+-----+-----+-----+-----+-----+ |0x100|0x101|0x102|0x103|0x104|0x105|0x106|0x107| +-----+-----+-----+-----+-----+-----+-----+-----+ +-----+-----+-----+-----+-----+-----+-----+-----+ | 26984 | 27756 | 111 | 0 | +-----+-----+-----+-----+-----+-----+-----+-----+ |0x100|0x101|0x102|0x103|0x104|0x105|0x106|0x107| +-----+-----+-----+-----+-----+-----+-----+-----+ +-----+-----+-----+-----+-----+-----+-----+-----+ | 1819044200 | 111 | +-----+-----+-----+-----+-----+-----+-----+-----+ |0x100|0x101|0x102|0x103|0x104|0x105|0x106|0x107| +-----+-----+-----+-----+-----+-----+-----+-----+
  • 5.
    UNDERSTANDING ERLANG TERMS ERLANG’SBUILDING BLOCK(PARTIALLY) ▸ Numbers ▸ 1, 2, 100 ▸ 1.0, 3.14 ▸ Atoms ▸ ok, true, false ▸ Tuples ▸ {}, {1, 2, 3}, {ok, 100} ▸ Lists ▸ [], [1, 2, 3] ▸ Maps ▸ #{name => “Jon Snow”, job => “King in the North”} ▸ Binaries ▸ <<“hello”>>, <<1, 2, 3>>
  • 6.
    UNDERSTANDING ERLANG TERMS ANAIVE IMPLEMENTATION xxxxxxxx xxxxxxxx xxxxxxxx xxxxx000 integer xxxxxxxx xxxxxxxx xxxxxxxx xxxxx001 float xxxxxxxx xxxxxxxx xxxxxxxx xxxxx010 atom xxxxxxxx xxxxxxxx xxxxxxxx xxxxx011 tuple xxxxxxxx xxxxxxxx xxxxxxxx xxxxx100 list xxxxxxxx xxxxxxxx xxxxxxxx xxxxx101 map xxxxxxxx xxxxxxxx xxxxxxxx xxxxx110 binary xxxxxxxx xxxxxxxx xxxxxxxx xxxxx111 *not in use*
  • 7.
    UNDERSTANDING ERLANG TERMS ERLANGTERM /* erts/emulator/beam/sys.h */ typedef unsigned long Eterm erts_align_attribute(sizeof(long)); typedef unsigned long Uint erts_align_attribute(sizeof(long)); typedef Uint UWord; /* erts/emulator/beam/erl_term.h */ typedef UWord Wterm; xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx 32-bits xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx 64-bits
  • 8.
    int i =100; printf(“%p”, &i); UNDERSTANDING ERLANG TERMS DATA ALIGNMENT PROPERTY +-----+-----+-----+-----+ | 100 | +-----+-----+-----+-----+ |0x100|0x101|0x102|0x103| +-----+-----+-----+-----+ +-----+-----+-----+-----+ | 100 | +-----+-----+-----+-----+ |0x204|0x205|0x206|0x207| +-----+-----+-----+-----+ +-----+-----+-----+-----+ | 100 | +-----+-----+-----+-----+ |0x40c|0x40d|0x40e|0x40f| +-----+-----+-----+-----+ 0001 0000 0000 0010 0000 0100 0011 0000 1000 0100 0000 1100 +-----+-----+-----+-----+ | 100 | +-----+-----+-----+-----+ |0x308|0x309|0x30a|0x30b| +-----+-----+-----+-----+
  • 9.
    UNDERSTANDING ERLANG TERMS ASTAGED TAG SCHEME FOR ERLANG xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx01 list xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx10 boxed xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 header xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx11 immediate 1 xxxxxxxx xxxxxxxx xxxxxxxx xxxx0011 pid xxxxxxxx xxxxxxxx xxxxxxxx xxxx0111 port xxxxxxxx xxxxxxxx xxxxxxxx xxxx1111 small int xxxxxxxx xxxxxxxx xxxxxxxx xxxx1011 immediate 2 xxxxxxxx xxxxxxxx xxxxxxxx xx001011 atom xxxxxxxx xxxxxxxx xxxxxxxx xx011011 catch 11111111 11111111 11111111 11111011 nil
  • 10.
    UNDERSTANDING ERLANG TERMS BOXEDHEADER xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 header xxxxxxxx xxxxxxxx xxxxxxxx xx000000 tuple xxxxxxxx xxxxxxxx xxxxxxxx xx000100 binary match context xxxxxxxx xxxxxxxx xxxxxxxx xx001000 pos big int xxxxxxxx xxxxxxxx xxxxxxxx xx001100 neg big int xxxxxxxx xxxxxxxx xxxxxxxx xx010000 reference xxxxxxxx xxxxxxxx xxxxxxxx xx010100 function xxxxxxxx xxxxxxxx xxxxxxxx xx011000 float xxxxxxxx xxxxxxxx xxxxxxxx xx011100 export xxxxxxxx xxxxxxxx xxxxxxxx xx100000 refc binary xxxxxxxx xxxxxxxx xxxxxxxx xx100100 heap binary xxxxxxxx xxxxxxxx xxxxxxxx xx101000 sub binary xxxxxxxx xxxxxxxx xxxxxxxx xx101100 *not used xxxxxxxx xxxxxxxx xxxxxxxx xx110000 external pid xxxxxxxx xxxxxxxx xxxxxxxx xx110100 external port xxxxxxxx xxxxxxxx xxxxxxxx xx111000 external reference xxxxxxxx xxxxxxxx xxxxxxxx xx111100 map
  • 11.
    UNDERSTANDING ERLANG TERMS IMMEDIATE1 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx11 immediate 1 xxxxxxxx xxxxxxxx xxxxxxxx xxxx1111 small int xxxxxxxx xxxxxxxx xxxxxxxx xxxx0011 pid xxxxxxxx xxxxxxxx xxxxxxxx xxxx0111 port
  • 12.
    UNDERSTANDING ERLANG TERMS IMMEDIATE1 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx11 immediate 1 xxxxxxxx xxxxxxxx xxxxxxxx xxxx1111 small int xxxxxxxx xxxxxxxx xxxxxxxx xxxx0011 pid xxxxxxxx xxxxxxxx xxxxxxxx xxxx0111 port
  • 13.
    UNDERSTANDING ERLANG TERMS SMALLINT xxxxxxxx xxxxxxxx xxxxxxxx xxxx1111 xxxxxxxx xxxxxxxx xxxxxxxx xxxx1111 32-bits xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxx1111 64-bits 01111111 11111111 11111111 11111111 TMAX 32 10000000 00000000 00000000 00001111 TMIN 32 -134,217,728 - 134,217,727 01111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 TMAX 64 10000000 00000000 00000000 00000000 00000000 00000000 00000000 00001111 TMIN 64 -576,460,752,303,423,488 - 576,460,752,303,423,487
  • 14.
    UNDERSTANDING ERLANG TERMS IMMEDIATE1 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx11 immediate 1 xxxxxxxx xxxxxxxx xxxxxxxx xxxx1111 small int xxxxxxxx xxxxxxxx xxxxxxxx xxxx0011 pid xxxxxxxx xxxxxxxx xxxxxxxx xxxx0111 port
  • 15.
    UNDERSTANDING ERLANG TERMS PID ▸Default 2^18 processes(262,144) ▸ Min 1024 ▸ Max 2^27 - 1 = 134,217,727, same as TMAX 32 xxxxxxxx xxxxxxxx xxxxxxxx xxxx0011 <0.157.0>
 00000000 00000000 00000100 11101000 00000000 00000000 00001001 11010011 <0.4520.2>
 00000000 00000000 00000101 01000001 00000000 00010001 00011010 10000011 % iex --erl "+P 1024" -S mix Interactive Elixir (1.5.2) - press Ctrl+C to exit (type h() ENTER for help) iex(1)> :erlang.system_info(:process_limit) 1024
  • 16.
    UNDERSTANDING ERLANG TERMS IMMEDIATE1 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx11 immediate 1 xxxxxxxx xxxxxxxx xxxxxxxx xxxx1111 small int xxxxxxxx xxxxxxxx xxxxxxxx xxxx0011 pid xxxxxxxx xxxxxxxx xxxxxxxx xxxx0111 port
  • 17.
    UNDERSTANDING ERLANG TERMS PORT ▸Default 2^16 ports (65536) ▸ Max 2^27 - 1 = 134,217,727, same as TMAX 32 xxxxxxxx xxxxxxxx xxxxxxxx xxxx0111
  • 18.
    UNDERSTANDING ERLANG TERMS IMMEDIATE2 xxxxxxxx xxxxxxxx xxxxxxxx xxxx1011 immediate 2 xxxxxxxx xxxxxxxx xxxxxxxx xx001011 atom xxxxxxxx xxxxxxxx xxxxxxxx xx011011 catch 11111111 11111111 11111111 11111011 nil
  • 19.
    UNDERSTANDING ERLANG TERMS IMMEDIATE2 xxxxxxxx xxxxxxxx xxxxxxxx xxxx1011 immediate 2 xxxxxxxx xxxxxxxx xxxxxxxx xx001011 atom xxxxxxxx xxxxxxxx xxxxxxxx xx011011 catch 11111111 11111111 11111111 11111011 nil
  • 20.
    UNDERSTANDING ERLANG TERMS ATOM ▸Default 2^20 = 1,048,576 ▸ Min 8192 ▸ Max 67108864 on 32-bits ▸ Max 2147483647 on 64-bits xxxxxxxx xxxxxxxx xxxxxxxx xx001011 xxxxxxxx xxxxxxxx xxxxxxxx xx001011 32-bits xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xx001011 64-bits 11111111 11111111 11111111 11001011 MAX 32 67,108,863 64MB 00000000 00000000 00000000 00011111 11111111 11111111 11111111 11001011 MAX 64 2,147,483,647 2GB
  • 21.
    UNDERSTANDING ERLANG TERMS IMMEDIATE2 xxxxxxxx xxxxxxxx xxxxxxxx xxxx1011 immediate 2 xxxxxxxx xxxxxxxx xxxxxxxx xx001011 atom xxxxxxxx xxxxxxxx xxxxxxxx xx011011 catch 11111111 11111111 11111111 11111011 nil
  • 22.
    UNDERSTANDING ERLANG TERMS CATCH ▸Stores the address of catch block xxxxxxxx xxxxxxxx xxxxxxxx xx011011
  • 23.
    UNDERSTANDING ERLANG TERMS IMMEDIATE2 xxxxxxxx xxxxxxxx xxxxxxxx xxxx1011 immediate 2 xxxxxxxx xxxxxxxx xxxxxxxx xx001011 atom xxxxxxxx xxxxxxxx xxxxxxxx xx011011 catch 11111111 11111111 11111111 11111011 nil
  • 24.
    UNDERSTANDING ERLANG TERMS NIL ▸[] ▸ Not nil in Elixir 11111111 11111111 11111111 11011011 11111111 11111111 11111111 11001011 32-bits 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11001011 64-bits
  • 25.
    UNDERSTANDING ERLANG TERMS PRIMARYTAG xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx01 list xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx10 boxed xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 header
  • 26.
    UNDERSTANDING ERLANG TERMS PRIMARYTAG xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx01 list xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx10 boxed xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 header
  • 27.
    UNDERSTANDING ERLANG TERMS LIST(CONS) ▸car ▸ cdr ▸ [car | cdr] xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx01 [1] 0x100 0x000000000000001f car: 1 0x108 0xfffffffffffffffb cdr: [] 0x100 00000000 00000000 00000001 00000000 0x101 00000000 00000000 00000001 00000001 [1, 2] 0x200 0x000000000000002f car: 2 0x208 0xfffffffffffffffb cdr: [] 0x210 0x000000000000001f car: 1 0x218 0x0000000000000201 cdr: [2] 0x210 00000000 00000000 00000011 00010000 0x211 00000000 00000000 00000011 00010001 [1 | 2] 0x300 0x000000000000001f car: 1 0x308 0x000000000000002f cdr: 2 0x300 00000000 00000000 00000011 00000000 0x301 00000000 00000000 00000011 00000001
  • 28.
    UNDERSTANDING ERLANG TERMS PRIMARYTAG xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx01 list xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx10 boxed xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 header
  • 29.
    UNDERSTANDING ERLANG TERMS BOXEDxxxxxxxx xxxxxxxx xxxxxxxx xxxxxx10 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx10
  • 30.
    UNDERSTANDING ERLANG TERMS BOXEDHEADER xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 header xxxxxxxx xxxxxxxx xxxxxxxx xx000000 tuple xxxxxxxx xxxxxxxx xxxxxxxx xx000100 binary match context xxxxxxxx xxxxxxxx xxxxxxxx xx001000 pos big int xxxxxxxx xxxxxxxx xxxxxxxx xx001100 neg big int xxxxxxxx xxxxxxxx xxxxxxxx xx010000 reference xxxxxxxx xxxxxxxx xxxxxxxx xx010100 function xxxxxxxx xxxxxxxx xxxxxxxx xx011000 float xxxxxxxx xxxxxxxx xxxxxxxx xx011100 export xxxxxxxx xxxxxxxx xxxxxxxx xx100000 refc binary xxxxxxxx xxxxxxxx xxxxxxxx xx100100 heap binary xxxxxxxx xxxxxxxx xxxxxxxx xx101000 sub binary xxxxxxxx xxxxxxxx xxxxxxxx xx101100 *not used xxxxxxxx xxxxxxxx xxxxxxxx xx110000 external pid xxxxxxxx xxxxxxxx xxxxxxxx xx110100 external port xxxxxxxx xxxxxxxx xxxxxxxx xx111000 external reference xxxxxxxx xxxxxxxx xxxxxxxx xx111100 map
  • 31.
    UNDERSTANDING ERLANG TERMS BOXEDHEADER xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 header xxxxxxxx xxxxxxxx xxxxxxxx xx000000 tuple xxxxxxxx xxxxxxxx xxxxxxxx xx000100 binary match context xxxxxxxx xxxxxxxx xxxxxxxx xx001000 pos big int xxxxxxxx xxxxxxxx xxxxxxxx xx001100 neg big int xxxxxxxx xxxxxxxx xxxxxxxx xx010000 reference xxxxxxxx xxxxxxxx xxxxxxxx xx010100 function xxxxxxxx xxxxxxxx xxxxxxxx xx011000 float xxxxxxxx xxxxxxxx xxxxxxxx xx011100 export xxxxxxxx xxxxxxxx xxxxxxxx xx100000 refc binary xxxxxxxx xxxxxxxx xxxxxxxx xx100100 heap binary xxxxxxxx xxxxxxxx xxxxxxxx xx101000 sub binary xxxxxxxx xxxxxxxx xxxxxxxx xx101100 *not used xxxxxxxx xxxxxxxx xxxxxxxx xx110000 external pid xxxxxxxx xxxxxxxx xxxxxxxx xx110100 external port xxxxxxxx xxxxxxxx xxxxxxxx xx111000 external reference xxxxxxxx xxxxxxxx xxxxxxxx xx111100 map
  • 32.
    UNDERSTANDING ERLANG TERMS TUPLExxxxxxxx xxxxxxxx xxxxxxxx xx000000 {} 0x100 0x0000000000000000 Arity(0) … 0000 0000 0x100 00000000 00000000 00000001 00000000 0x102 00000000 00000000 00000001 00000010 {1} 0x200 0x0000000000000040 Arity(1) … 0100 0000 0x208 0x000000000000001f 1 0x200 00000000 00000000 00000010 00000000 0x202 00000000 00000000 00000010 00000010 {1, 2} 0x300 0x0000000000000080 Arity(2) … 1000 0000 0x308 0x000000000000001f 1 0x310 0x000000000000002f 2 0x300 00000000 00000000 00000011 00000000 0x302 00000000 00000000 00000011 00000010
  • 33.
    UNDERSTANDING ERLANG TERMS BOXEDHEADER xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 header xxxxxxxx xxxxxxxx xxxxxxxx xx000000 tuple xxxxxxxx xxxxxxxx xxxxxxxx xx000100 binary match context xxxxxxxx xxxxxxxx xxxxxxxx xx001000 pos big int xxxxxxxx xxxxxxxx xxxxxxxx xx001100 neg big int xxxxxxxx xxxxxxxx xxxxxxxx xx010000 reference xxxxxxxx xxxxxxxx xxxxxxxx xx010100 function xxxxxxxx xxxxxxxx xxxxxxxx xx011000 float xxxxxxxx xxxxxxxx xxxxxxxx xx011100 export xxxxxxxx xxxxxxxx xxxxxxxx xx100000 refc binary xxxxxxxx xxxxxxxx xxxxxxxx xx100100 heap binary xxxxxxxx xxxxxxxx xxxxxxxx xx101000 sub binary xxxxxxxx xxxxxxxx xxxxxxxx xx101100 *not used xxxxxxxx xxxxxxxx xxxxxxxx xx110000 external pid xxxxxxxx xxxxxxxx xxxxxxxx xx110100 external port xxxxxxxx xxxxxxxx xxxxxxxx xx111000 external reference xxxxxxxx xxxxxxxx xxxxxxxx xx111100 map
  • 34.
    UNDERSTANDING ERLANG TERMS BIGINT xxxxxxxx xxxxxxxx xxxxxxxx xx001x00 (1 <<< 59) - 1 01111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111 MAX small int (1 <<< 59) 00000000_00000000_00000000_00000000_10000110_10010011_10001000_00101010 boxed 00000000_00000000_00000000_00000000_00000000_00000000_00000000_01001000 pos bignum 00001000_00000000_00000000_00000000_00000000_00000000_00000000_00000000 (1 <<< 59) + 1 00000000_00000000_00000000_00000000_10000110_10010011_10001000_00101010 boxed 00000000_00000000_00000000_00000000_00000000_00000000_00000000_01001000 pos bignum 00001000_00000000_00000000_00000000_00000000_00000000_00000000_00000001 (-1 <<< 59) - 1 00000000_00000000_00000000_00000000_10000110_10010011_10001000_00101010 boxed 00000000_00000000_00000000_00000000_00000000_00000000_00000000_01001100 neg bignum 00001000_00000000_00000000_00000000_00000000_00000000_00000000_00000001 (-1 <<< 59) 10000000_00000000_00000000_00000000_00000000_00000000_00000000_00001111 MIN small int
  • 35.
    UNDERSTANDING ERLANG TERMS BOXEDHEADER xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 header xxxxxxxx xxxxxxxx xxxxxxxx xx000000 tuple xxxxxxxx xxxxxxxx xxxxxxxx xx000100 binary match context xxxxxxxx xxxxxxxx xxxxxxxx xx001000 pos big int xxxxxxxx xxxxxxxx xxxxxxxx xx001100 neg big int xxxxxxxx xxxxxxxx xxxxxxxx xx010000 reference xxxxxxxx xxxxxxxx xxxxxxxx xx010100 function xxxxxxxx xxxxxxxx xxxxxxxx xx011000 float xxxxxxxx xxxxxxxx xxxxxxxx xx011100 export xxxxxxxx xxxxxxxx xxxxxxxx xx100000 refc binary xxxxxxxx xxxxxxxx xxxxxxxx xx100100 heap binary xxxxxxxx xxxxxxxx xxxxxxxx xx101000 sub binary xxxxxxxx xxxxxxxx xxxxxxxx xx101100 *not used xxxxxxxx xxxxxxxx xxxxxxxx xx110000 external pid xxxxxxxx xxxxxxxx xxxxxxxx xx110100 external port xxxxxxxx xxxxxxxx xxxxxxxx xx111000 external reference xxxxxxxx xxxxxxxx xxxxxxxx xx111100 map
  • 36.
    UNDERSTANDING ERLANG TERMS FLOAT ▸IEEE754 xxxxxxxx xxxxxxxx xxxxxxxx xx011000 0.0 00000000_00000000_00000000_00000000_10000110_10010011_10001000_00101010 boxed 00000000_00000000_00000000_00000000_00000000_00000000_00000000_01011000 float 00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000 1.0 00000000_00000000_00000000_00000000_10000110_10010011_10001000_00101010 boxed 00000000_00000000_00000000_00000000_00000000_00000000_00000000_01011000 float 00111111_11110000_00000000_00000000_00000000_00000000_00000000_00000000 -1.0 00000000_00000000_00000000_00000000_10000110_10010011_10001000_00101010 boxed 00000000_00000000_00000000_00000000_00000000_00000000_00000000_01011000 float 10111111_11110000_00000000_00000000_00000000_00000000_00000000_00000000
  • 37.
    UNDERSTANDING ERLANG TERMS BOXEDHEADER xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 header xxxxxxxx xxxxxxxx xxxxxxxx xx000000 tuple xxxxxxxx xxxxxxxx xxxxxxxx xx000100 binary match context xxxxxxxx xxxxxxxx xxxxxxxx xx001000 pos big int xxxxxxxx xxxxxxxx xxxxxxxx xx001100 neg big int xxxxxxxx xxxxxxxx xxxxxxxx xx010000 reference xxxxxxxx xxxxxxxx xxxxxxxx xx010100 function xxxxxxxx xxxxxxxx xxxxxxxx xx011000 float xxxxxxxx xxxxxxxx xxxxxxxx xx011100 export xxxxxxxx xxxxxxxx xxxxxxxx xx100000 refc binary xxxxxxxx xxxxxxxx xxxxxxxx xx100100 heap binary xxxxxxxx xxxxxxxx xxxxxxxx xx101000 sub binary xxxxxxxx xxxxxxxx xxxxxxxx xx101100 *not used xxxxxxxx xxxxxxxx xxxxxxxx xx110000 external pid xxxxxxxx xxxxxxxx xxxxxxxx xx110100 external port xxxxxxxx xxxxxxxx xxxxxxxx xx111000 external reference xxxxxxxx xxxxxxxx xxxxxxxx xx111100 map
  • 38.
    UNDERSTANDING ERLANG TERMS HEAPBINARY xxxxxxxx xxxxxxxx xxxxxxxx xx100100 <<>> 00000000_00000000_00000000_00000000_10000110_10010011_10001000_00101010 boxed 00000000_00000000_00000000_00000000_00000000_00000000_00000000_01100100 heap binary 00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000 “hello” 00000000_00000000_00000000_00000000_10000110_10010011_10001000_00101010 boxed 00000000_00000000_00000000_00000000_00000000_00000000_00000000_10100100 heap binary 00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000101 size(5) 00000000_00000000_00000000_01101111_01101100_01101100_01100101_01101000 o l l e h “hello world!” 00000000_00000000_00000000_00000000_10000110_10010011_10001000_00101010 boxed 00000000_00000000_00000000_00000000_00000000_00000000_00000000_11100100 heap binary 00000000_00000000_00000000_00000000_00000000_00000000_00000000_00001100 size(12) 01101111_01110111_00100000_01101111_01101100_01101100_01100101_01101000 o w s o l l e h 00000000_00000000_00000000_00000000_00100001_01100100_01101100_01110010 ! d l r
  • 39.
    UNDERSTANDING ERLANG TERMS MYTHWALKTHROUGH ▸ Tail-recursive functions are much faster than body- recursive functions
  • 40.
    UNDERSTANDING ERLANG TERMS TAIL-RECURSIVEVS BODY-RECURSIVE defmodule Foo do def add1_tail(list) do do_add1_tail(list, []) end defp do_add1_tail([], acc) do Enum.reverse(acc) end defp do_add1_tail([h | t], acc) do do_add1_tail(t, [h + 1 | acc]) end def add1_body([]) do [] end def add1_body([h | t]) do [h + 1 | add1_body(t)] end end
  • 41.
    UNDERSTANDING ERLANG TERMS TAIL-RECURSIVE |BEAM STACK | | Address | Contents | |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1af8 | 0x0000000042fcae49 | [1,2,3,4,5] | 0x0000000015ac1af0 | 0x0000000019ede830 | BEAM PC 'Elixir.Foo':run1/0 + 0x5 |--------------------|--------------------| |--------------------|--------------------| |--------------------|--------------------| | Address | Contents | | H E A P | defmodule Foo do def run1 do add1_tail([1, 2, 3, 4, 5]) end def add1_tail(list) do do_add1_tail(list, []) end defp do_add1_tail([], acc) do Enum.reverse(acc) end defp do_add1_tail([h | t], acc) do do_add1_tail(t, [h + 1 | acc]) end end
  • 42.
    UNDERSTANDING ERLANG TERMS TAIL-RECURSIVE |BEAM STACK | | Address | Contents | |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1af8 | 0x0000000042fcae59 | [2,3,4,5] | 0x0000000015ac1af0 | 0xfffffffffffffffb | [] | 0x0000000015ac1ae8 | 0x000000000000001f | 1 | 0x0000000015ac1ae0 | 0x0000000019ede830 | BEAM PC 'Elixir.Foo':run1/0 + 0x5 |--------------------|--------------------| |--------------------|--------------------| |--------------------|--------------------| | Address | Contents | | H E A P | defmodule Foo do def run1 do add1_tail([1, 2, 3, 4, 5]) end def add1_tail(list) do do_add1_tail(list, []) end defp do_add1_tail([], acc) do Enum.reverse(acc) end defp do_add1_tail([h | t], acc) do do_add1_tail(t, [h + 1 | acc]) end end
  • 43.
    UNDERSTANDING ERLANG TERMS TAIL-RECURSIVE |BEAM STACK | | Address | Contents | |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1af8 | 0x0000000042fcae69 | [3,4,5] | 0x0000000015ac1af0 | 0x0000000015ac13c9 | [2] | 0x0000000015ac1ae8 | 0x000000000000002f | 2 | 0x0000000015ac1ae0 | 0x0000000019ede830 | BEAM PC 'Elixir.Foo':run1/0 + 0x5 |--------------------|--------------------| |--------------------|--------------------| | 0x0000000015ac13d0 | 0xfffffffffffffffb | [] | 0x0000000015ac13c8 | 0x000000000000002f | 2 |--------------------|--------------------| | Address | Contents | | H E A P | defmodule Foo do def run1 do add1_tail([1, 2, 3, 4, 5]) end def add1_tail(list) do do_add1_tail(list, []) end defp do_add1_tail([], acc) do Enum.reverse(acc) end defp do_add1_tail([h | t], acc) do do_add1_tail(t, [h + 1 | acc]) end end
  • 44.
    UNDERSTANDING ERLANG TERMS TAIL-RECURSIVE |BEAM STACK | | Address | Contents | |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1af8 | 0x0000000042fcae79 | [4,5] | 0x0000000015ac1af0 | 0x0000000015ac13d9 | [3,2] | 0x0000000015ac1ae8 | 0x000000000000003f | 3 | 0x0000000015ac1ae0 | 0x0000000019ede830 | BEAM PC 'Elixir.Foo':run1/0 + 0x5 |--------------------|--------------------| |--------------------|--------------------| | 0x0000000015ac13e0 | 0x0000000015ac13c9 | [2] | 0x0000000015ac13d8 | 0x000000000000003f | 3 | 0x0000000015ac13d0 | 0xfffffffffffffffb | [] | 0x0000000015ac13c8 | 0x000000000000002f | 2 |--------------------|--------------------| | Address | Contents | | H E A P | defmodule Foo do def run1 do add1_tail([1, 2, 3, 4, 5]) end def add1_tail(list) do do_add1_tail(list, []) end defp do_add1_tail([], acc) do Enum.reverse(acc) end defp do_add1_tail([h | t], acc) do do_add1_tail(t, [h + 1 | acc]) end end
  • 45.
    UNDERSTANDING ERLANG TERMS TAIL-RECURSIVE |BEAM STACK | | Address | Contents | |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1af8 | 0x0000000042fcae89 | [5] | 0x0000000015ac1af0 | 0x0000000015ac13e9 | [4,3,2] | 0x0000000015ac1ae8 | 0x000000000000004f | 4 | 0x0000000015ac1ae0 | 0x0000000019ede830 | BEAM PC 'Elixir.Foo':run1/0 + 0x5 |--------------------|--------------------| |--------------------|--------------------| | 0x0000000015ac13f0 | 0x0000000015ac13d9 | [3,2] | 0x0000000015ac13e8 | 0x000000000000004f | 4 | 0x0000000015ac13e0 | 0x0000000015ac13c9 | [2] | 0x0000000015ac13d8 | 0x000000000000003f | 3 | 0x0000000015ac13d0 | 0xfffffffffffffffb | [] | 0x0000000015ac13c8 | 0x000000000000002f | 2 |--------------------|--------------------| | Address | Contents | | H E A P | defmodule Foo do def run1 do add1_tail([1, 2, 3, 4, 5]) end def add1_tail(list) do do_add1_tail(list, []) end defp do_add1_tail([], acc) do Enum.reverse(acc) end defp do_add1_tail([h | t], acc) do do_add1_tail(t, [h + 1 | acc]) end end
  • 46.
    UNDERSTANDING ERLANG TERMS TAIL-RECURSIVE |BEAM STACK | | Address | Contents | |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1af8 | 0xfffffffffffffffb | [] | 0x0000000015ac1af0 | 0x0000000015ac13f9 | [5,4,3,2] | 0x0000000015ac1ae8 | 0x000000000000005f | 5 | 0x0000000015ac1ae0 | 0x0000000019ede830 | BEAM PC 'Elixir.Foo':run1/0 + 0x5 |--------------------|--------------------| |--------------------|--------------------| | 0x0000000015ac1400 | 0x0000000015ac13e9 | [4,3,2] | 0x0000000015ac13f8 | 0x000000000000005f | 5 | 0x0000000015ac13f0 | 0x0000000015ac13d9 | [3,2] | 0x0000000015ac13e8 | 0x000000000000004f | 4 | 0x0000000015ac13e0 | 0x0000000015ac13c9 | [2] | 0x0000000015ac13d8 | 0x000000000000003f | 3 | 0x0000000015ac13d0 | 0xfffffffffffffffb | [] | 0x0000000015ac13c8 | 0x000000000000002f | 2 |--------------------|--------------------| | Address | Contents | | H E A P | defmodule Foo do def run1 do add1_tail([1, 2, 3, 4, 5]) end def add1_tail(list) do do_add1_tail(list, []) end defp do_add1_tail([], acc) do Enum.reverse(acc) end defp do_add1_tail([h | t], acc) do do_add1_tail(t, [h + 1 | acc]) end end
  • 47.
    UNDERSTANDING ERLANG TERMS TAIL-RECURSIVE |BEAM STACK | | Address | Contents | |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1af8 | 0x0000000015ac1409 | [6,5,4,3,2] | 0x0000000015ac1af0 | 0x0000000019ede830 | BEAM PC 'Elixir.Foo':run1/0 + 0x5 |--------------------|--------------------| |--------------------|--------------------| | 0x0000000015ac1410 | 0x0000000015ac13f9 | [5,4,3,2] | 0x0000000015ac1408 | 0x000000000000006f | 6 | 0x0000000015ac1400 | 0x0000000015ac13e9 | [4,3,2] | 0x0000000015ac13f8 | 0x000000000000005f | 5 | 0x0000000015ac13f0 | 0x0000000015ac13d9 | [3,2] | 0x0000000015ac13e8 | 0x000000000000004f | 4 | 0x0000000015ac13e0 | 0x0000000015ac13c9 | [2] | 0x0000000015ac13d8 | 0x000000000000003f | 3 | 0x0000000015ac13d0 | 0xfffffffffffffffb | [] | 0x0000000015ac13c8 | 0x000000000000002f | 2 |--------------------|--------------------| | Address | Contents | | H E A P | defmodule Foo do def run1 do add1_tail([1, 2, 3, 4, 5]) end def add1_tail(list) do do_add1_tail(list, []) end defp do_add1_tail([], acc) do Enum.reverse(acc) end defp do_add1_tail([h | t], acc) do do_add1_tail(t, [h + 1 | acc]) end end
  • 48.
    UNDERSTANDING ERLANG TERMS TAIL-RECURSIVE |BEAM STACK | | Address | Contents | |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1b08 | 0x0000000015ac1459 | [2,3,4,5,6] | 0x0000000015ac1b00 | 0x000000001525a148 | BEAM PC normal-process-exit |--------------------|--------------------| |--------------------|--------------------| | 0x0000000015ac1460 | 0x0000000015ac1449 | [3,4,5,6] | 0x0000000015ac1458 | 0x000000000000002f | 2 | 0x0000000015ac1450 | 0x0000000015ac1439 | [4,5,6] | 0x0000000015ac1448 | 0x000000000000003f | 3 | 0x0000000015ac1440 | 0x0000000015ac1429 | [5,6] | 0x0000000015ac1438 | 0x000000000000004f | 4 | 0x0000000015ac1430 | 0x0000000015ac1419 | [6] | 0x0000000015ac1428 | 0x000000000000005f | 5 | 0x0000000015ac1420 | 0xfffffffffffffffb | [] | 0x0000000015ac1418 | 0x000000000000006f | 6 | 0x0000000015ac1410 | 0x0000000015ac13f9 | [5,4,3,2] | 0x0000000015ac1408 | 0x000000000000006f | 6 | 0x0000000015ac1400 | 0x0000000015ac13e9 | [4,3,2] | 0x0000000015ac13f8 | 0x000000000000005f | 5 | 0x0000000015ac13f0 | 0x0000000015ac13d9 | [3,2] | 0x0000000015ac13e8 | 0x000000000000004f | 4 | 0x0000000015ac13e0 | 0x0000000015ac13c9 | [2] | 0x0000000015ac13d8 | 0x000000000000003f | 3 | 0x0000000015ac13d0 | 0xfffffffffffffffb | [] | 0x0000000015ac13c8 | 0x000000000000002f | 2 |--------------------|--------------------| | Address | Contents | | H E A P | defmodule Foo do def run1 do add1_tail([1, 2, 3, 4, 5]) end def add1_tail(list) do do_add1_tail(list, []) end defp do_add1_tail([], acc) do Enum.reverse(acc) end defp do_add1_tail([h | t], acc) do do_add1_tail(t, [h + 1 | acc]) end end
  • 49.
    UNDERSTANDING ERLANG TERMS BODY-RECURSIVE |BEAM STACK | | Address | Contents | |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1af8 | 0x0000000042fcae59 | [2,3,4,5] | 0x0000000015ac1af0 | 0x000000000000001f | 1 |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1ae8 | 0x0000000019ede8b0 | BEAM PC 'Elixir.Foo':run2/0 + 0x5 |--------------------|--------------------| |--------------------|--------------------| |--------------------|--------------------| | Address | Contents | | H E A P | defmodule Foo do def run2 do add1_body([1, 2, 3, 4, 5]) end def add1_body([]) do [] end def add1_body([h | t]) do [h + 1 | add1_body(t)] end end
  • 50.
    UNDERSTANDING ERLANG TERMS BODY-RECURSIVE |BEAM STACK | | Address | Contents | |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1af8 | 0x000000000000002f | 2 | 0x0000000015ac1af0 | 0x0000000019ede8b0 | BEAM PC 'Elixir.Foo':run2/0 + 0x5 |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1ae8 | 0x0000000042fcae69 | [3,4,5] | 0x0000000015ac1ae0 | 0x000000000000002f | 2 | 0x0000000015ac1ad8 | 0x0000000019ede000 | BEAM PC ‘Elixir.Foo':add1_body/1 + 0x12 |--------------------|--------------------| |--------------------|--------------------| |--------------------|--------------------| | Address | Contents | | H E A P | defmodule Foo do def run2 do add1_body([1, 2, 3, 4, 5]) end def add1_body([]) do [] end def add1_body([h | t]) do [h + 1 | add1_body(t)] end end
  • 51.
    UNDERSTANDING ERLANG TERMS BODY-RECURSIVE |BEAM STACK | | Address | Contents | |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1af8 | 0x000000000000002f | 2 | 0x0000000015ac1af0 | 0x0000000019ede8b0 | BEAM PC 'Elixir.Foo':run2/0 + 0x5 |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1ae8 | 0x000000000000003f | 3 | 0x0000000015ac1ae0 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12 |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1ad8 | 0x0000000042fcae79 | [4,5] | 0x0000000015ac1ad0 | 0x000000000000003f | 3 | 0x0000000015ac1ac8 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12 |--------------------|--------------------| |--------------------|--------------------| |--------------------|--------------------| | Address | Contents | | H E A P | defmodule Foo do def run2 do add1_body([1, 2, 3, 4, 5]) end def add1_body([]) do [] end def add1_body([h | t]) do [h + 1 | add1_body(t)] end end
  • 52.
    UNDERSTANDING ERLANG TERMS BODY-RECURSIVE |BEAM STACK | | Address | Contents | |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1af8 | 0x000000000000002f | 2 | 0x0000000015ac1af0 | 0x0000000019ede8b0 | BEAM PC 'Elixir.Foo':run2/0 + 0x5 |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1ae8 | 0x000000000000003f | 3 | 0x0000000015ac1ae0 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12 |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1ad8 | 0x000000000000004f | 4 | 0x0000000015ac1ad0 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12 |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1ac8 | 0x0000000042fcae89 | [5] | 0x0000000015ac1ac0 | 0x000000000000004f | 4 | 0x0000000015ac1ab8 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12 |--------------------|--------------------| |--------------------|--------------------| |--------------------|--------------------| | Address | Contents | | H E A P | defmodule Foo do def run2 do add1_body([1, 2, 3, 4, 5]) end def add1_body([]) do [] end def add1_body([h | t]) do [h + 1 | add1_body(t)] end end
  • 53.
    UNDERSTANDING ERLANG TERMS BODY-RECURSIVE |BEAM STACK | | Address | Contents | |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1af8 | 0x000000000000002f | 2 | 0x0000000015ac1af0 | 0x0000000019ede8b0 | BEAM PC 'Elixir.Foo':run2/0 + 0x5 |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1ae8 | 0x000000000000003f | 3 | 0x0000000015ac1ae0 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12 |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1ad8 | 0x000000000000004f | 4 | 0x0000000015ac1ad0 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12 |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1ac8 | 0x000000000000005f | 5 | 0x0000000015ac1ac0 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12 |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1ab8 | 0xfffffffffffffffb | [] | 0x0000000015ac1ab0 | 0x000000000000005f | 5 | 0x0000000015ac1aa8 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12 |--------------------|--------------------| |--------------------|--------------------| |--------------------|--------------------| | Address | Contents | | H E A P | defmodule Foo do def run2 do add1_body([1, 2, 3, 4, 5]) end def add1_body([]) do [] end def add1_body([h | t]) do [h + 1 | add1_body(t)] end end
  • 54.
    UNDERSTANDING ERLANG TERMS BODY-RECURSIVE |BEAM STACK | | Address | Contents | |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1af8 | 0x000000000000002f | 2 | 0x0000000015ac1af0 | 0x0000000019ede8b0 | BEAM PC 'Elixir.Foo':run2/0 + 0x5 |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1ae8 | 0x000000000000003f | 3 | 0x0000000015ac1ae0 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12 |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1ad8 | 0x000000000000004f | 4 | 0x0000000015ac1ad0 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12 |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1ac8 | 0x000000000000005f | 5 | 0x0000000015ac1ac0 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12 |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1ab8 | 0x000000000000006f | 6 | 0x0000000015ac1ab0 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12 |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1aa8 | 0x0000000019ede000 | BEAM PC 'Elixir.Foo':add1_body/1 + 0x12 |--------------------|--------------------| |--------------------|--------------------| |--------------------|--------------------| | Address | Contents | | H E A P | defmodule Foo do def run2 do add1_body([1, 2, 3, 4, 5]) end def add1_body([]) do [] end def add1_body([h | t]) do [h + 1 | add1_body(t)] end end
  • 55.
    UNDERSTANDING ERLANG TERMS BODY-RECURSIVE |BEAM STACK | | Address | Contents | |--------------------|--------------------| BEAM ACTIVATION RECORD | 0x0000000015ac1b08 | 0x0000000015ac1409 | [2,3,4,5,6] | 0x0000000015ac1b00 | 0x000000001525a148 | BEAM PC normal-process-exit |--------------------|--------------------| |--------------------|--------------------| | 0x0000000015ac1410 | 0x0000000015ac13f9 | [3,4,5,6] | 0x0000000015ac1408 | 0x000000000000002f | 2 | 0x0000000015ac1400 | 0x0000000015ac13e9 | [4,5,6] | 0x0000000015ac13f8 | 0x000000000000003f | 3 | 0x0000000015ac13f0 | 0x0000000015ac13d9 | [5,6] | 0x0000000015ac13e8 | 0x000000000000004f | 4 | 0x0000000015ac13e0 | 0x0000000015ac13c9 | [6] | 0x0000000015ac13d8 | 0x000000000000005f | 5 | 0x0000000015ac13d0 | 0xfffffffffffffffb | [] | 0x0000000015ac13c8 | 0x000000000000006f | 6 |--------------------|--------------------| | Address | Contents | | H E A P | defmodule Foo do def run2 do add1_body([1, 2, 3, 4, 5]) end def add1_body([]) do [] end def add1_body([h | t]) do [h + 1 | add1_body(t)] end end
  • 56.
    UNDERSTANDING ERLANG TERMS MYTHDEMYSTIFY ▸ Use the version that makes your code cleaner (hint: it is usually the body-recursive version) ▸ A tail-recursive function that does not need to reverse the list at the end is faster than a body-recursive function
  • 57.
    UNDERSTANDING ERLANG TERMS RESOURCES ▸The Seven Myths of Erlang Performance ▸ http://erlang.org/doc/efficiency_guide/myths.html ▸ A Staged Tag Scheme for Erlang(2000) ▸ http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.142.2827 ▸ The Erlang Type System and Tags(The BEAM Book) ▸ https://happi.github.io/theBeamBook/#CH-TypeSystem ▸ Data Types Memory Layout(BEAM-WISDOM) ▸ http://beam-wisdoms.clau.se/en/latest/indepth-memory-layout.html ▸ Erlang/OTP source code ▸ https://github.com/erlang/otp/blob/master/erts/emulator/beam/erl_term.h ▸ ETerm library ▸ https://github.com/sunboshan/eterm