Exploring Erlang

Author: Bob Ippolito
Date: August 2007
Venue:C4[1]

What's Erlang?

Erlang at Mochi Media

MochiAds, MochiBot

Maybe you've seen our ads?

images/im-in-ur-maze.jpg

Functional

Collections

list:
linked list: [1, 2, 3] = [1 | [2, 3]]
tuple:
{fixed_size, array, of, stuff}

Basic Types

atom:
effectively a constant string, also seen 'quoted'
binary:
<<"contiguous chunk of bytes", 9999:64/little>>
integer, float:
unbounded integers, 64-bit floating point
ref:
unique reference

Other Erlang Data Types

fun:
function reference, can be sent to other processes or serialized
pid:
reference to a process, maybe on another node
port:
reference to a driver, socket, pipe, etc. Similar to pid

Not Erlang Types

boolean:
true, false (atoms)
character:
$c = 99
string:
"abc" = [$a, $b, $c] = [97, 98, 99]

Variables

Simple Pattern Matching

A = some_atom,
B = some_atom,

A = B,

{some_atom, some_atom} = {A, B},

%% _ (underscore) matches anything
{A, _} = {some_atom, has_a_bucket},

%% Next line will fail with a bad match
A = another_atom.

Multiple Clauses, Guards

case date() of

    {2007, 8, N} when N >= 10, N =< 12 ->
        c4_1;

    {2006, 10, N} when N == 20; N == 21 ->
        c4_0;

    _ ->
        not_c4

end.

Bit Syntax

<<Bits:5, _:3, _/binary>> = Binary,

Padding = (8 - ((5 + Bits * 4) band 7)),

<<Bits:5,
  0:Bits, Width:Bits/signed,
  0:Bits, Height:Bits/signed,
  _:Padding,
  FrameRate:16/little,
  FrameCount:16/little>> = Binary.

Punctuation?!

comma ( , ):
Delimits expressions
semicolon ( ; ):
Delimits clauses
period ( . ):
Ends the last (or only) clause

Syntax is... different

images/128297985360157500xcusemeyoug.jpg

Integer Accumulator (JS)

function sum(list) {
    var acc = 0;
    for (var i = 0; i < list.length; i++) {
        acc += list[i];
    }
    return acc;
}

Bad Integer Accumulator

sum([]) ->
    0;
sum([N | Rest]) ->
    %% Not a tail call.
    N + sum(Rest).

Shouldn't do this - use tail calls instead.

Integer Accumulator

sum(L) ->
    sum(L, 0).

sum([], Acc) ->
    Acc;
sum([N | Rest], Acc) ->
    sum(Rest, N + Acc).

Better:

lists:sum(L)

List Accumulator (JS)

function seq(min, max) {
    var acc = [];
    for (var i = min; i <= max; i++) {
        acc.push(i);
    }
    return acc;
}

List Accumulator

seq(Min, Max) ->
    seq(Min, Max, []).

seq(N, Max, Acc) when N =< Max ->
    seq(1 + N, Max, [N | Acc]);
seq(_N, _Max, Acc) ->
    lists:reverse(Acc).

Better:

lists:seq(Min, Max)

Modules

Trivial Module

-module(c4).
-export([hello_world/0]).

%% Call this with c4:hello_world().
hello_world() ->
    hello_world.

Compiling from the shell

1> c(c4).
{ok,c4}

2> c4:hello_world().
hello_world

Compile everything

1> make:all([load]).
Recompile: c4
up_to_date

2> c4:hello_world().
hello_world

Processes

Creating a process (Server)

-module(c4_adder).
-export([start/0, loop/1, add/2]).

start() -> spawn(?MODULE, loop, [0]).

Creating a process (API)

add(N, Pid) ->
    Pid ! {{add, N}, self()},
    receive
        {add_result, Result} ->
            {ok, Result}
    after
         10 ->
            {error, timeout}
    end.

Creating a process (Guts)

loop(Count) ->
    receive
        {{add, N}, Sender} ->
            Sender ! {add_result, N + Count},
            ?MODULE:loop(N + Count);
        Unknown ->
            io:format("UNKNOWN: ~p~n",
                      [Unknown]),
            ?MODULE:loop(N + Count)
    end.

Creating a process (Example)

1> Adder = c4_adder:start().
<0.35.0>

2> c4_adder:add(10, Adder).
{ok,10}

3> Adder ! unexpected_message.
unexpected_message
UNKNOWN: unexpected_message

4> c4_adder:add(20, Adder).
{ok,30}

Registered Processes

1> register(my_adder, c4_adder:start()).
true

2> whereis(my_adder).
<0.35.0>

3> c4_adder:add(10, my_adder).
{ok,10}

4> exit(whereis(my_adder), kill).
true

Distributed

Multiple Nodes

images/we-await-ur-instrucsions.jpg

Starting Multiple Nodes

$ erl -name bob@127.0.0.1 -cookie secret

1> register(adder, c4_adder:start()).
true
2> c4_adder:add(10, adder).
{ok,10}

$ erl -name alice@127.0.0.1 -cookie secret

1> c4_adder:add(10, {adder, 'bob@127.0.0.1'}).
{ok,20}

Monitoring Processes

images/error-reboot-plz.jpg

Monitoring Processes (Example)

1> register(my_adder, c4_adder:start()).
true

2> Mon = erlang:monitor(process, my_adder).
#Ref<0.0.0.117>

3> exit(whereis(my_adder), kill).
true

4> receive Msg -> io:format("~p~n", [Msg]) end.
{'DOWN', #Ref<0.0.0.117>, process,
 {my_adder, nonode@nohost}, killed}
ok

Linked Processes

High-reliability

Supervisors

Supervisor Tree (Diagram)

images/i-has-minions.jpg

Behaviours

gen_server adder (API)

-module(c4_adder_otp).
-behaviour(gen_server).
-export([start/0, add/2, stop/1]).
-export([init/1, terminate/2,
         handle_cast/2, handle_call/3]).

start() ->
    gen_server:start_link(?MODULE, 0, []).

add(N, Pid) ->
    gen_server:call(Pid, {add, N}).

stop(Pid) -> gen_server:cast(Pid, stop).

gen_server adder (Guts)

init(Count) ->
    {ok, Count}.

terminate(_Reason, _Count) ->
    ok.

handle_cast(stop, Count) ->
    {stop, normal, Count}.

handle_call({add, N}, _From, Count) ->
    {reply, N + Count, N + Count}.

gen_server adder (Example)

1> {ok, Adder} = c4_adder_otp:start().
{ok,<0.35.0>}

2> c4_adder_otp:add(10, Adder).
10
3> c4_adder_otp:add(10, Adder).
20

4> c4_adder_otp:stop(Adder).
ok

Demo Time

images/uninterested.jpg

More Information