erlang: the language and the platform

78
ERLANG the language and the platform Gabriele Lana [email protected]

Upload: gabriele-lana

Post on 15-Jan-2015

1.011 views

Category:

Technology


1 download

DESCRIPTION

 

TRANSCRIPT

Page 1: Erlang: the language and the platform

ERLANGthe language and

the platform

Gabriele [email protected]

Page 2: Erlang: the language and the platform

• Designed and implemented by Joe Armstrong in 1986

• Was originally a proprietary language within Ericsson

• Was released as open source in 1998

Page 3: Erlang: the language and the platform

A New Way to Program That’s 20 Years Old

Page 4: Erlang: the language and the platform

Joe Armstrong @ QCon 2009

Page 5: Erlang: the language and the platform

Joe Armstrong @ QCon 2009

Page 6: Erlang: the language and the platform

Erlang (BEAM) emulator version 5.5.6 [source][smp:1] [async-threads:0] [hipe] [kernel-poll:true]

Eshell V5.5.6 (abort with ^G)1>

Erlang Shell

Page 7: Erlang: the language and the platform

1> 3.3

2> 1 + 2008.2009

3> 849274893217458392017483921 * 78932489321748392107483291.67035381440116040485849541847226463097212333368664011

Syntax: Number

Page 8: Erlang: the language and the platform

1> atom.atom

2> anythingStartingWithLowercaseLetter. anythingStartingWithLowercaseLetter

3> 'anything enclosed in single quotes'.'anything enclosed in single quotes'

Syntax: Atom

Page 9: Erlang: the language and the platform

1> true.true

2> false.false

3> is_atom(true).true

4> is_boolean(true).true

Syntax: Boolean

Page 10: Erlang: the language and the platform

1> "foo"."foo"

2> "anything enclosed in double quotes"."anything enclosed in double quotes"

Syntax: String

Page 11: Erlang: the language and the platform

1> [].[]

2> [ 1 ].[1]

3> [ first ].[first]

4> [ "first" ].["first"]

5> [ 1, first, "first" ].[1,first,"first"]

Syntax: List

Page 12: Erlang: the language and the platform

1> [ 72, 101, 108, 108, 111 ]."Hello"

2> $H.72

3> [ $H, $e, $l, $l, $o ]."Hello"

Syntax: Strings are Lists

Page 13: Erlang: the language and the platform

1> { 1, 2, 3 }.{1,2,3}

2> { name, "Gabriele" }.{name,"Gabriele"}

3> { coder, { name, "Gabriele" }, { language, "Erlang" } }.{coder,{name,"Gabriele"},{language,"Erlang"}}

Syntax: Tuple

Page 14: Erlang: the language and the platform

1> <<“Hello”>>.<<“Hello”>>

2> <<1:1,8:7>>. <<136>>

3> erlang:binary_to_list(<<1:32/big>>).[0,0,0,1]

4> erlang:binary_to_list(<<1:32/little>>).[1,0,0,0]

Syntax: Binaries

Page 15: Erlang: the language and the platform

1> 1 = 1.1

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

3> catch 1 = 2.{'EXIT',{{badmatch,2},[{erl_eval,expr,3}]}}

Pattern Matching

Page 16: Erlang: the language and the platform

1> X.* 1: variable 'X' is unbound

2> X = 5.5

3> X.5

4> X = 6.** exception error: no match of right hand side value 6

Pattern Matching: Binding Variables

Page 17: Erlang: the language and the platform

1> Coder = { coder, { name, "Gabriele" } }.{coder,{name,"Gabriele"}}

2> { person, { name, "Gabriele" } } = Coder.** exception error: no match of right hand side value {coder,{name,"Gabriele"}}

3> { coder, { name, "Gabriele" } } = Coder.{coder,{name,"Gabriele"}}

Pattern Matching: Destructuring

Page 18: Erlang: the language and the platform

4> { coder, { name, CoderName } } = Coder. {coder,{name,"Gabriele"}}

5> CoderName."Gabriele"

6> AnotherCoderName = "Matteo"."Matteo"

7> { coder, { name, AnotherCoderName } } = Coder.** exception error: no match of right hand side value {coder,{name,"Gabriele"}}

Pattern Matching: Destructuring

Page 19: Erlang: the language and the platform

1> [ First, Last ] = [ first, last ].[first,last]

2> First.first

3> Last.last

Pattern Matching: List

Page 20: Erlang: the language and the platform

4> [ Head | Tail ] = [ 1, 2, 3, 4, 5 ]. [1,2,3,4,5]

5> Head.1

6> Tail.[2,3,4,5]

Pattern Matching: List

Page 21: Erlang: the language and the platform

1> [ First, Second | Others ] = [ 1, 2, 3, 4, 5 ].[1,2,3,4,5]

2> First.1

3> Second.2

4> Others.[3,4,5]

Pattern Matching: List

Page 22: Erlang: the language and the platform

1> { X, Y, X } = { { abc, 12 }, 42, { abc, 12 } }.{{abc,12},42,{abc,12}}

2> X.{abc,12}

3> Y.42

Pattern Matching: In Deep

Page 23: Erlang: the language and the platform

1> { X, Y, X } = { { abc, 12 }, 42, true }.** exception error: no match of right hand side value {{abc,12},42,true}

2> { X, Y, _ } = { { abc, 12 }, 42, true }.{{abc,12},42,true}

Pattern Matching: In Deep

Page 24: Erlang: the language and the platform

-module(examples).-export([ hello/0 ]).

hello() -> "Hello World!".

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

2> examples:hello()."Hello World!"

Function

examples.erl

Page 25: Erlang: the language and the platform

Syntax: Punctuation

• Periods (.) end everything except when

• Semicolons (;) end clauses

• and Commas (,) separate expressions

Page 26: Erlang: the language and the platform

-export([ double/1 ]).

double(0) -> 0;double(Number) -> Number * 2.

1> examples:double(0).0

2> examples:double(4).8

Function: Pattern Mathing & Clause

Page 27: Erlang: the language and the platform

double(0) -> 0;double(Number) when is_integer(Number) -> Number * 2.

1> examples:double(4).8

2> examples:double(foo).** exception error: no function clause matching examples:double(foo)

Function: Guard

Page 28: Erlang: the language and the platform

double(0) -> 0;double(Number) when is_integer(Number) -> Number * 2;double(AnythingElse) -> io:format("I don't know how to double ~p~n", [ AnythingElse ]), error.

1> examples:double(foo).I don't know how to double fooerror

Function: Guard

Page 29: Erlang: the language and the platform

multiplyBy(Multiplier) -> fun(Number) -> Number * Multiplier end.

1> Double = examples:multiplyBy(2).#Fun<examples.0.46516809>2> Double(4).83> MultiplyBy4 = examples:multiplyBy(4).#Fun<examples.0.46516809>4> MultiplyBy4(4).16

Function: Anonymous & Closure

Page 30: Erlang: the language and the platform

printList([]) -> ok;printList([ Item | List ]) -> io:format("~p~n", [ Item ]), printList(List).

1> examples:printList([ 1, 2, 3, 4 ]).1234ok

Function: Tail Recursion

Page 31: Erlang: the language and the platform

foreach(_Function, []) -> ok;foreach(Function, [ Item | List ]) -> Function(Item), foreach(Function, List).

1> examples:foreach(fun(Item) -> io:format("~p~n", [ Item ])end, [ 1, 2, 3, 4 ]).1234

Function: High Order Function

Page 32: Erlang: the language and the platform

foreach(Function, List) -> lists:foreach(Function, List).

1> examples:foreach(fun(Item) -> io:format("~p~n", [ Item ])end, [ 1, 2, 3, 4 ]).1234ok

Function: High Order Function

Page 33: Erlang: the language and the platform

3> lists:foreach(fun(Item) -> io:format("~p~n", [ Item ])end, [ 1, 2, 3, 4 ]).1234ok

Function: High Order Function

Page 34: Erlang: the language and the platform

names(Coders) -> lists:map(fun({ coder, { name, CoderName } }) -> CoderName end, Coders).

1> examples:names([ 1> { coder, { name, "Gabriele" } },1> { coder, { name, "Matteo" } } 1> ]).["Gabriele","Matteo"]

List Functions: Map

Page 35: Erlang: the language and the platform

triplets(UpTo) when is_number(UpTo), UpTo >= 2 -> [ { A, B, C } || A <- lists:seq(2, UpTo), B <- lists:seq(2, UpTo), C <- lists:seq(2, UpTo), A * A + B * B =:= C * C, A + B + C =< UpTo ].

1> examples:triplets(10).[{3,4,5},{4,3,5},{6,8,10},{8,6,10}]

Syntax: List Comprehension

Page 36: Erlang: the language and the platform

sum(Numbers) -> lists:foldl(fun(Number, Sum) -> Sum + Number end, 0, Numbers).

1> examples:sum([ 1, 2, 3, 4, 5 ]).15

List Functions: Fold/Reduce

Page 37: Erlang: the language and the platform

sum(Numbers) -> lists:foldl(fun (Number, Sum) when is_integer(Number) -> Sum + Number; (_Number, Sum) -> Sum end, 0, Numbers).

1> examples:sum([ 1, 2, 3, foo, 4, bar, 5 ]).15

List Functions: Fold/Reduce

Page 38: Erlang: the language and the platform

fizzbuzz(UpTo) -> lists:map(fun(Counter) -> if (Counter rem 15) =:= 0 -> fizzbuzz; (Counter rem 3) =:= 0 -> fizz; (Counter rem 5) =:= 0 -> buzz; true -> Counter end end, lists:seq(1, UpTo)).

1> examples:fizzbuzz(16).[1,2,fizz,4,buzz,fizz,7,8,fizz,buzz,11,fizz,13,14,fizzbuzz,16]

Example: FizzBuzz

Page 39: Erlang: the language and the platform

the secret weapon

Page 40: Erlang: the language and the platform

Joe Armstrong @ QCon 2009

Page 41: Erlang: the language and the platform

Scalability: Concurrency

• Any function (named or anonymous) can become a process

• A process is simply a function executing in parallel

• A process shares nothing with other processes• A process is extremely lightweight: a modern

systems can accommodate literally millions of Erlang processes

Page 42: Erlang: the language and the platform

1> processes:profileSpawnFor(1000). Spawned 1.000 processes in 10 (4) millisecondsok

2> processes:profileSpawnFor(10000). Spawned 10.000 processes in 96 (40) millisecondsok

3> processes:profileSpawnFor(100000).Spawned 100.000 processes in 884 (510) millisecondsok

Scalability: Concurrency

Page 43: Erlang: the language and the platform

Scalability: Concurrency

• The “!” operator sends messages• Asynchronous• Order guaranted

• The “receive” statement matches messages• One call to receive, one message removed

from the process message queue• Uses pattern matching to select messages

Page 44: Erlang: the language and the platform

1> Pid = spawn(fun() ->1> receive1> die -> io:format("Bye~n")1> end1> end).<0.33.0>

Scalability: Concurrency

Page 45: Erlang: the language and the platform

2> is_process_alive(Pid).true

3> Pid ! die.Byedie

4> is_process_alive(Pid).false

Scalability: Concurrency

Page 46: Erlang: the language and the platform

profileSpawnFor(Number) -> Processes = for(1, Number, fun() -> spawn(fun() -> wait() end) end), lists:foreach(fun(Pid) -> Pid ! die end, Processes).

wait() -> receive die -> void end.

Scalability: Concurrency

Page 47: Erlang: the language and the platform

factorials(Numbers) -> map(fun(Number) -> factorial(Number) end, Numbers).

Scalability: Inherently Distributed

Page 48: Erlang: the language and the platform

factorials(Numbers) -> map(fun(Number) -> factorial(Number) end, Numbers).

factorials(Numbers) ->

pmap(fun(Number) -> factorial(Number)

end, Numbers, 20).

Distributed on20 different

processes

Scalability: Inherently Distributed

Page 49: Erlang: the language and the platform

factorials(Numbers) -> map(fun(Number) -> factorial(Number) end, Numbers).

factorials(Numbers) ->

pmap(fun(Number) -> factorial(Number)

end, Numbers, 20, nodes()).

Distributed on 20 different processes for each available nodes

on the cluster

Scalability: Inherently Distributed

Page 50: Erlang: the language and the platform

Scalability: Inherently Distributedpmap(Map, Elements, Nodes) -> Spawn = case length(Nodes) of 0 -> fun spawn/1; Length -> NextNode = fun() -> nth(random:uniform(Length), Nodes) end, fun(F) -> spawn(NextNode(), F) end end, Parent = self(), Pids = [ Spawn(fun() -> Parent ! { self(), (catch Map(Element)) } end) || Element <- Elements ], [ receive { Pid, ReturnedValue } -> ReturnedValue end || Pid <- Pids ].

Page 51: Erlang: the language and the platform

Referentially Transparent:if a function can be

replaced with its value without changing the

program

Testability: Referential Transparency

Page 52: Erlang: the language and the platform

the function behavior is defined purely in terms of its input parameters

and return value.

Testability: Referential Transparency

Page 53: Erlang: the language and the platform

no Las Vegas

effect!

Testability: Referential Transparency

Page 54: Erlang: the language and the platform

Testability: EUnit-include_lib("eunit/include/eunit.hrl").

should_be_able_to_pick_next_player_id_test() -> NoPlayers = [], ?assertEqual(1, next_player_id(NoPlayers)), OnePlayer = [ { 1, aPlayer } ], ?assertEqual(2, next_player_id(OnePlayer)),

TwoConsecutivePlayers = [ { 1, aPlayer }, { 2, aPlayer } ], ?assertEqual(3, next_player_id(TwoConsecutivePlayers)),

TwoNonConsecutivePlayers = [ { 1, aPlayer }, { 3, aPlayer } ], ?assertEqual(2, next_player_id(TwoNonConsecutivePlayers)), ...

sector.hrl

Page 55: Erlang: the language and the platform

Testability: EUnit

should_be_able_to_pick_next_player_id_test() -> ... SectorFullOfPlayers = [ { PlayerId, aPlayer } || PlayerId <- seq(1, ?MAX_NUMBER_OF_PLAYERS) ]

OnePlayerToFullSector = subtract({ 5, aPlayer }, SectorFullOfPlayers), ?assertEqual(5, next_player_id(OnePlayerToFullSector)),

?assertException(error, _, next_player_id(SectorFullOfPlayers)),

true.

sector.hrl

Page 56: Erlang: the language and the platform

Testability: EUnit

next_player_id(Players) -> min( subtract( seq(1, ?MAX_NUMBER_OF_PLAYERS), [ PlayerId || { PlayerId, _Player } <- Players ] ) ).

-ifdef(?TEST).-include_lib("../test/sector.hrl").-endif.

sector.erl

Page 57: Erlang: the language and the platform

Testability: EUnit

next_player_id(Players) -> min( subtract( list_of_possible_ids(), list_of_used_ids(Players) ) ).

-ifdef(?TEST).-include_lib("../test/sector.hrl").-endif.

sector.erl

Page 58: Erlang: the language and the platform

Testability: Mocking Processes

a_player_cant_join_a_full_sector_test() -> ... SectorFull = spawn(?MODULE, loop, [ Status, Players ]), AskToJoinTo = fun(SectorToJoin) -> SectorToJoin ! { join, self(), aPolarity }, receive { kickout, Reason } -> { kickout, Reason }; UnexpectedResponse -> { error, unexpected, UnexpectedResponse } after 100 -> { error, timeout } end end,

?assertMatch({ kickout, sector_full }, AskToJoinTo(SectorFull)).

sector.hrl

Page 59: Erlang: the language and the platform

Readability: Sometimes...

{ tcp, Socket, Message } -> case Message of ... <<16#9:8,_:64,PlayerBlasterId:16,PlayerBlastedId:16,AmountOfEnergy:8>> -> Player ! { blast, PlayerBlasterId, PlayerBlastedId, AmountOfEnergy };

<<16#A:8,_:64,FromPlayerWithId:16,ChatMessage:64/binary>> -> Player ! { chat, FromPlayerWithId, ChatMessage };

<<16#C:8,_:64,PlayerTakerId:16,EntityTakenId:16>> -> Player ! { take, PlayerTakerId, EntityTakenId }; ... end

peer.erl

Page 60: Erlang: the language and the platform

Readability: Sometimes...

<<16#9:8,_:64,PlayerBlasterId:16,PlayerBlastedId:16,AmountOfEnergy:8>> -> Player ! { blast, PlayerBlasterId, PlayerBlastedId, AmountOfEnergy };

peer.erl

! Blast!! Request to Blast a Player (blast)|1:length|1:0x9|8:timestamp|2:blasterId|2:blastedId|1:amountOfEnergy|

protocol.md

Page 61: Erlang: the language and the platform

Reliability: Fault Tollerance is Easier

• The “link” function can link processes• When a process die the linked processes receive

a message { ‘EXIT’, Died, Reason } • A monitor process could respawn the died ones

or cleanup the system

Page 62: Erlang: the language and the platform

-module(killer).-export([ start/0 ]).

start() -> Victim = spawn(fun victim/0), Killer = spawn(fun killer/0), Witness = spawn(fun witness/0),

Witness ! { watch, Victim }, Killer ! { kill, Victim }.

killer.erl

Reliability: Fault Tollerance is Easier

Page 63: Erlang: the language and the platform

killer() -> receive { kill, Victim } -> io:format("killer: I will kill you!!!~n"), Victim ! die end.

victim() -> receive die -> io:format("victim: Ahhhhhh!!!~n") end.

killer.erl

Reliability: Fault Tollerance is Easier

Page 64: Erlang: the language and the platform

witness() -> receive { watch, Victim } -> process_flag(trap_exit, true), link(Victim), witness(); { 'EXIT', _WhoDied, _WhyHeDied } -> io:format("witness: Help!!!~n") end.

killer.erl

Reliability: Fault Tollerance is Easier

Page 65: Erlang: the language and the platform

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

2> killer:start().killer: I will kill you!!!victim: Ahhhhhh!!!witness: Help!!!

Reliability: Fault Tollerance is Easier

Page 66: Erlang: the language and the platform

Reliability: Fault Tollerance is Easier

Page 67: Erlang: the language and the platform

PeerSoc

ket

Player

1

Sector

1Universe

PeerPlayer

2

PeerPlayer

3

PeerPlayer

4

Reliability: Fault Tollerance is Easier

Page 68: Erlang: the language and the platform

PeerSoc

ket

Player

1

Sector

1Universe

Player

2

Player

3

Watcher

Link Link

Link

Link

Link

Link

Reliability: Fault Tollerance is Easier

Page 69: Erlang: the language and the platform

PeerSoc

ket

Player

1

Sector

1

Player

2

Player

3

Watcher

{ ‘EXIT’, Peer }

{ leave, Player }

{ leaved, Player }

{ leave, Player }

Reliability: Fault Tollerance is Easier

Page 70: Erlang: the language and the platform

Player

1

Sector

1

Player

2

Player

3

Watcher

Peer

Peer

Peer

Universe

{ ‘EXIT’, Sector, _ }

{ remove, Sector }

{ leaved, Player }

{ lea

ved,

... }

Reliability: Fault Tollerance is Easier

Page 71: Erlang: the language and the platform

Scalability: Show me some Numbers!ping-pong on EC2

http://github.com/gabrielelana/ping-pong

Page 72: Erlang: the language and the platform

Scalability: Show me some Numbers!5 messages/second

Pingers ErlangRTD/Median

ErlangRTD/Deviation

ErlangErrors

JavaRTD/Median

JavaRTD/Deviation

JavaErrors

50 0.1 0.35 0 0.1 0.69 0

100 0.24 0.41 0 0.17 0.4 0

500 0.73 0.7 0 2.96 2.8 0

1000 0.65 6.5 0 12.7 10.10 0

5000 6.17 27.7 0 1007.37 908.32 0

10000 49.34 31.4 51 20372.6 6451.46 1912

Page 73: Erlang: the language and the platform

Scalability: Show me some Numbers!10 messages/second

Pingers ErlangRTD/Median

ErlangRTD/Deviation

ErlangErrors

JavaRTD/Median

JavaRTD/Deviation

JavaErrors

50 0.64 0.39 0 0.2 0.67 0

100 0.74 0.46 0 0.5 1.97 0

500 1.5 5.36 0 4.03 7.44 0

1000 1.81 10.6 0 32.22 125.43 0

5000 46.17 46.46 3 1204.8 3674.6 314

Page 74: Erlang: the language and the platform

Scalability: Show me some Numbers!20 messages/second

Pingers ErlangRTD/Median

ErlangRTD/Deviation

ErlangErrors

JavaRTD/Median

JavaRTD/Deviation

JavaErrors

50 0.9 0.8 0 0.4 0.77 0

100 1.6 11.35 0 1.4 14.95 0

500 4.92 11.06 0 5.67 15.41 6

1000 11.43 25.18 0 159.36 278.2 2

5000 51.72 54.19 280 462.31 223.1 1400

Page 75: Erlang: the language and the platform

Why Erlang?

Damien Katz @ Ruby Fringe 2008

Page 76: Erlang: the language and the platform

... no silver bullets: Weaknesses

• Flat namespaces• Obscure documentation • Few mytical examples of success• Very bad I/O performance• Vary bad string manipulation performance• Lack of libraries and code examples• No strong IDE and tools support

Page 77: Erlang: the language and the platform

Hard Gained Insights

• Don’t miss tail-call recursion• Asynchronous is good• Small functions are good• When in doubt create a new process• Think early what to do when a process die

Page 78: Erlang: the language and the platform

Some books are coming out