I thought I could kill two birds with one stone and teach myself a little Go and Erlang by converting the following example code (taken from http://blog.smartbear.com/programming/an-introduction-to-the-go-language-boldly-going-where-no-man-has-ever-gone-before/) from Go to Erlang:
package main
import (
"fmt"
"time"
)
type Ball struct{ hits int }
func main() {
table := make(chan *Ball)
go player("ping", table)
go player("pong", table)
table <- new(Ball) // game on; toss the ball
time.Sleep(1 * time.Second)
<-table // game over; grab the ball
}
func player(name string, table chan *Ball) {
for {
ball := <-table
ball.hits++
fmt.Println(name, ball.hits)
time.Sleep(100 * time.Millisecond)
table <- ball
}
}
However I failed. The code basically creates a shared counter (the ball) and sends it back and forth between the two goroutines (the players). So far so good. But how do I do something similar in Erlang? My problems were:
A variable is not mutable in erlang, that means that during the evaluation of one function, the variable is either unbound, either set to a value that cannot change. But you can recall the same function with a new value build from the former one, recursively. The value is stored in a variable generally called the state, and it is modified when a message is received. This is the basic behaviour of a server.
In your example you don't really need a variable to contain the counter since this value will be exchange between the 2 players. I can be contained in the message exchanged between them for example in a tuple {count,V}.
The only way to communicate between 2 processes is message passing. The simplest syntax is Pid ! Message, where Pid is the process ID if the receiver, and Message , well the message :o) (Pid can be replaced by a name if the process is registered).
with this you can write:
-module(pingpong).
-export([start/0,player/1,stop/1]).
player(Name) ->
receive
{count,From,Val} ->
io:format("~p received the ball for the ~p th exchange~n",[Name,Val]),
ok = timer:sleep(500),
From ! {count,self(),Val+1},
player(Name);
{start,To} ->
io:format("~p start the exchange~n",[Name]),
To ! {count,self(),1},
player(Name);
stop -> gameover
end.
start() ->
Ping = spawn(?MODULE,player,[ping]),
Pong = spawn(?MODULE,player,[pong]),
Ping ! {start,Pong},
{Ping,Pong}.
stop(P1) -> P1 ! stop.
in the shell:
1> c(pingpong).
{ok,pingpong}
2> {P1,P2} = pingpong:start().
ping start the exchange
pong received the ball for the 1 th exchange
{<0.39.0>,<0.40.0>}
ping received the ball for the 2 th exchange
pong received the ball for the 3 th exchange
ping received the ball for the 4 th exchange
pong received the ball for the 5 th exchange
ping received the ball for the 6 th exchange
pong received the ball for the 7 th exchange
ping received the ball for the 8 th exchange
pong received the ball for the 9 th exchange
ping received the ball for the 10 th exchange
pong received the ball for the 11 th exchange
ping received the ball for the 12 th exchange
pong received the ball for the 13 th exchange
ping received the ball for the 14 th exchange
pong received the ball for the 15 th exchange
ping received the ball for the 16 th exchange
pong received the ball for the 17 th exchange
ping received the ball for the 18 th exchange
pong received the ball for the 19 th exchange
ping received the ball for the 20 th exchange
pong received the ball for the 21 th exchange
ping received the ball for the 22 th exchange
pong received the ball for the 23 th exchange
ping received the ball for the 24 th exchange
3> pingpong:stop(P1).
stop
4> pingpong:stop(P2).
stop
5>