Erlang Examples: GUIs and Error Handling

This is part of a series on the Erlang Exercises which is a great set of programming problems that challenge you to implement solutions to some common Erlang problems. I’m going to share some of my solutions to these problems.

Robustness in Erlang, and use of a graphics package

Excercise: Create a window containing three buttons: Quit , Spawn , Error.
The Spawn button shall create a child process which displays an identical window.
The Quit button should kill the window and its child windows.
The Error button should cause a runtime error that kills the window (and its children), this window shall then be restarted by its parent.

-module(gui).
-export([init/0]).
 
init() ->
    S = gs:start(),
    Win = gs:create(window, S, [{width, 350}, {height, 100}]),
    gs:create(button, quit, Win, [{label, {text, "Quit"}}, {x, 0}]),
    gs:create(button, spawn, Win, [{label, {text, "Spawn"}}, {x, 100}]),
    gs:create(button, error, Win, [{label, {text, "Error"}}, {x, 200}]),
    gs:config(Win, {map, true}),
    loop().
 
loop() ->
    receive
        {gs, spawn, click, _, _} ->
            Pid = spawn(?MODULE, init, []),
            handle_error(self(), Pid),
            io:format("got here~n",[]),
            loop();
        {gs, quit, click, _, _} ->
            io:format("quitting~n",[]),
            gs:stop();
        {gs, error, click, _, _} ->
            erlang:error(errorclick);
        exit ->
            bye
    end.
 
handle_error(MasterPid, Pid) ->
    spawn(fun() ->
                  process_flag(trap_exit, true),
                  link(Pid),
                  receive 
                      {'EXIT', Pid, {errorclick, _}} ->
                          io:format(" ~p died :~n",[Pid]),
                          MasterPid ! {gs, spawn, click, a, b};
                      _ ->
                          io:format(" really quitting :~n", []),
                          MasterPid ! exit
                  end
          end).

gs

The gs code is all GUI code. It just goes to show that you can use FP to create GUIs even if it’s not quite as intuitive as it might be in an OO language. It creates a windows with a series of buttons on it.

handle_error

This handle_error code shows linking a Process to another error handler process. That spawns a process whose sole purpose is to listen for errors from the main process. If an {‘EXIT’, Pid, {errorclick, _}} error is received the error handler sends a message back asking the MasterPid to spawn a new window.

Erlang Examples: Talk with Erlang

This is part of a series on the Erlang Exercises which is a great set of programming problems that challenge you to implement solutions to some common Erlang problems. I’m going to share some of my solutions to these problems.

Implementing Talk with Distributed Erlang

Make a simple Talk program that makes it possible to chat with friends at other nodes/hosts.
Hints: Your program should consist of two registered processes one for reading from the terminal and the other one for recieving messages from the other node then writing them to the terminal.

-module(talk2).
-compile(export_all).
start() ->
    OtherNode = clean(io:get_line('What node? ')),
    FullNode = string:concat(OtherNode, "@localhost"),
    io:format("talking to: ~s~n", [FullNode]),
    register(receiver, spawn(?MODULE, receiver, [])),
    register(sender, spawn(?MODULE, sender, [list_to_atom(FullNode)])),
    get_input().
get_input() ->
    Message = clean(io:get_line('Talk: ')),
    case string:equal("exit!", Message) of
        true ->
            receiver ! done,
            sender ! done;
        false ->
            talk(Message),
            get_input()
    end.
talk(Message) ->
    sender ! {send, Message}.
sender(OtherNode) ->
    receive
        {send, Message} ->
            rpc:call(OtherNode, talk2, send_message, [Message]),
            sender(OtherNode);
        done ->
            void
    end.
send_message(Message) ->
    receiver ! {message, Message}.
receiver() ->
    receive
        {message, Message} ->
            io:format("~s~n", [Message]),
            receiver();
        done ->
            void
    end.
clean(Data) ->
    string:strip(Data, both, $\n).

Explanation

This is functionally similar to Erlang Talk with Sockets. The difference is that it is doing Erlang-to-Erlang only communication taking advantage of Erlang’s distributed functionality. The Socket example could have been made to interact with any programming language that can do socket programming.

start() ->
This starts the application by asking the user for the name of the other Erlang node to talk to. Erlang nodes are started by running them with a node name erl -name foo. That along with host information are used to talk to a remote node.

So, first using io:get_line(‘What node? ‘) we ask the user then name of the other node. Then we spawn 2 processes. One to receive messages and one to send them. The interesting part here is the use of the register function. It takes an atom and a process id. The register function basically binds a pid to an atom and creates a globally accessible pid. It just simplifies the code a bit so you don’t have to pass those pids to all of the other functions.

get_input() ->
This is the main user input loop. It asks the user for a message and then sends that message to the sender process. io:get_line(‘Talk: ‘) waits for user input before it returns, so only after a user types something and hits return will this function continue. If the case string:equal(“exit!”, Message) do evaluates to true, then the sender and receiver processes are told to exit and the program ends naturally. Otherwise the message is sent.

talk(Message) ->
This function sends the message to the sender process.

sender(OtherNode) ->
This is the function that is running as the sender process. It is initialized with the remote OtherNode information. It receives messages and forwards them to the OtherNode. The rpc:call(OtherNode, talk2, send_message, [Message]), call invokes the send_message function running on the remote node.

send_message(Message) ->
This is really an RPC helper method that passes messages it get to the process running the receive function.

receiver() ->
The receiver is the function that is being run as the receiver process. It listens for messages and when it gets one it prints it out to the user.

Thoughts

The other interesting way to solve this would be to actually spawn processes remotely on the other node. The code can then have a reference to a pid running on the remote node and can pass messages to it directly without using the RPC approach. This would allow one side of the conversation to initiate it without the other knowing about it.


register(remote_receiver, spawn(OtherNode, talk2, receiver, [])),
remote_receiver ! "Hello".

An exercise I’ll leave up to you!

Erlang Examples: Talk with Sockets

This is part of a series on the Erlang Exercises which is a great set of programming problems that challenge you to implement solutions to some common Erlang problems. I’m going to share some of my solutions to these problems.

Erlang using UNIX sockets

Do you want to talk with a friend on another machine? Shouldn’t it be nice to have a shell connected to your friend and transfer messages in between?
This can be implemented using the client/server concept with a process on each side listening to a socket for messages.

-module(talk).
-compile(export_all).
start(LocalPort, RemotePort) ->
    ServerPid = spawn(?MODULE, start_server, [LocalPort]),
    cli(RemotePort, ServerPid).
cli(RemotePort, ServerPid) ->
    Data = clean(io:get_line('Message: ')),
    case should_stop(Data) of
        true ->
            ServerPid ! done;
        false ->
            spawn(?MODULE, send, [RemotePort, Data]),
            cli(RemotePort, ServerPid)
    end.
clean(Data) ->
    string:strip(Data, both, $\n).
should_stop(Str) ->
    0 =:= string:len(Str).
start_server(Port) ->
    case gen_tcp:listen(Port, [binary, {packet, 4},
                               {reuseaddr, true},
                               {active, true}]) of
        {ok, Listen} ->
            server(Listen);
        {error, Reason} ->
            {error, Reason}
    end.
server(Listen) ->
    case gen_tcp:accept(Listen) of
        {ok, Socket} ->
            server_loop(Socket),
            server(Listen);
        _ ->
            ok
    end.
server_loop(Socket) ->
    receive
        done ->
            gen_tcp:close(Socket),
            io:format("Server socket closed~n");
        {tcp, Socket, Bin} ->
            Str = clean(binary_to_term(Bin)),
            io:format("~p~n", [Str]),
            case should_stop(Str) of
                true ->
                    void;
                false ->
                    server_loop(Socket)
            end;
        {tcp_closed, _Socket} ->
            ok
    end.
send(Port, Data) ->
    case gen_tcp:connect("localhost", Port, [binary, {packet, 4}]) of
        {ok, Socket} ->
            gen_tcp:send(Socket, term_to_binary(Data)),
            gen_tcp:close(Socket);
        {error, Reason} ->
            {error, Reason}
    end.

Explanation

start(LocalPort, RemotePort) ->
The entry point to the talk program. This spawns a new start_server process that will handle opening a socket and listening for messages from a remote client. It then runs the command line interface and waits for data from the user to send to the remote port.

cli(RemotePort, ServerPid) ->
This is the loop that will get the data from the user and send it to the remote port.

clean(Data)
This is a simple function that removes the newlines from the end of the data sent to the client.

should_stop(Str)
This is a simple function that determines whether the client and server should shut down. The rule is that if it’s an empty string then the processes should stop.

start_server(Port) ->
This function gets run in a process and opens a Listening socket. It then hands off to server(Listen) -> to handle dealing with new incoming socket connections.

server(Listen) ->
The server gets a new Socket when an incoming connection connects to the Listening port. It then goes into a receive state and waits for an incoming connection to send it data. The receive state is handled in the server_loop.

send(Port, Data) ->
This is the client side of the application. It connects to a remote port and sends the data to that port.

case … of
In a number of these functions you see a common idiom:

case fun() of
    SomeMatch ->
        Do something;
    AnotherMatch ->
        Do something else
end

With socket connections and many others it is common to return a tuple like {ok, Val} when the function call is successful and will return {error, Reason} or a similar tuple when there is an error in the function. The case statement is just an easy way to handle these differences.

Erlang Example: Star Messages

This is part of a series on the Erlang Exercises which is a great set of programming problems that challenge you to implement solutions to some common Erlang problems. I’m going to share some of my solutions to these problems.

Interaction between processes, Concurrency

3) Write a function which starts N processes in a star, and sends a message to each of them M times. After the messages have been sent the processes should terminate gracefully.

-module(star).
-export([start/2, loop/0, sendMessage/2]).
start(0, _) ->
    io:format("done~n", []);
start(N, M) ->
    timer:sleep(random:uniform(10) * 100),
    LoopPid = spawn(?MODULE, loop, []),
    spawn(?MODULE, sendMessage, [M, LoopPid]),
    start(N - 1, M).
sendMessage(0, Pid) ->
    Pid ! done;
sendMessage(M, Pid) ->
    timer:sleep(random:uniform(5) * 100),
    Pid ! M,
    sendMessage(M - 1, Pid).
loop() ->
    receive
        done ->
            io:format("* Process: ~10w, Message#: terminate!~n", [self()]);
        R ->
            io:format(": Process: ~10w, Message#: ~w ..~n", [self(), R]),
            loop()
    end.

Explanation

start(N, M)
The entry point to the code defines the Number of processes to start and the number of Messages to pass. timer:sleep(random:uniform(10) * 100), is just to demonstrate that things are actually happening concurrently. Without this the program usually runs to fast and everything is sequential. LoopPid = spawn(?MODULE, loop, []), creates a new process running the loop function. That process is set up to receive messages and print some information out. spawn(?MODULE, sendMessage, [M, LoopPid]), is then called to create a new process whose job it is to send each LoopPid (really the nodes in the star) M number of messages. Finally start(N – 1, M). is called tail recursively with one less Node count.

start(0, _)
This function is called or matched when the tail recursion from start(N, M) finally gets down to the value where N is zero. In that case we no longer want to spawn processes so we just write “done” and exit the function.

sendMessage(M, Pid)
Following a similar pattern to the start function this counts down M to zero and sends M as a message to the given Pid. The tail recursion handles decrementing to the count of M until the pattern (0, Pid) is matched at which point sendMessage(0, Pid) is matched and the Pid is sent the ‘done’ message.

loop()
This is the function that is run as the individual processes or the “points of the star”. Its job is to receive messages passed to it. When done -> is matched by a message, the process will print out some information and then end gracefully. R -> represents a message being passed with a single value that is anything other than the atom ‘done’. When it is matched the value is printed and the process waits for another message by calling back to itself with loop()

Thoughts

One of the interesting things to me is the tail recursion of Erlang and other Functional Programming Languages. This accomplished the same thing as a looping construct without using for or while or any of those usual imperative methods.

Erlang Example: Min and Max Element of a List

This is part of a series on the Erlang Exercises which is a great set of programming problems that challenge you to implement solutions to some common Erlang problems. I’m going to share some of my solutions to these problems.

Simple recursive programs

1. Write a function lists1:min(L) which returns the mini- mum element of the list L.
2. Write a function lists1:max(L) which returns the maximum element of the list L.

(I’m only showing the max version since the min is basically just the change of the guard clause.)

-module(mylists).
-export([max/1]).
max([H|T]) ->
    max(H, T).
max(M, []) ->
    M;
max(M, [H|L]) when M > H ->
    max(M, L);
max(_M, [H|L]) ->
    max(H,L).

Explanation

max([H|T])
This code is composed of a public, exported function and a private function. max([H|T]) defines a function that takes a list. The slightly funny notation [H|T] is an operation that removes the head value (the zeroth element] from a list and assigns the head value to H and the remainder of the list to T. Think of the list as a stack, and you’ve just popped the stack. This method then delegates the remainder of the work to the internal, 2 value max function.

max(M, [H|L]) when M > H ->
This method is the main part of the internal, 2 value max function. The interesting piece here is when M > Hmax(_M, [H|L]) -> which acts as a fall-through because the ones that don’t match the first will call this. You can see those two functions take either M or H and pass that as the current Max value.

max(M, []) ->
The final piece of the internal max function is max(M, []) ->. This is the end state of the function. The [] clause in the function arguments pattern matches an empty list. Based on those previous 2 parts of the function definition this is fulfilling the final case where the current max value has been compared to the last element in the list.

Example

List = [1,2,4,6,5].
mylists:max(List).

So what happens is:

  1. max([1 | [2,4,6,5]])
  2. max(1, [2 | [4,6,5]])
  3. max(2, [4 | [6,5]])
  4. max(4, [6 | [5]])
  5. max(6, [5 | []]) when M > H
  6. max(6, [])

Erlang Exercises: Ring Messages

Erlang Exercises has a great little series of programming problems that challenge you to implement solutions to some common Erlang problems. It’s a great way to learn the language. I’m going to share some of my solutions to these problems. Maybe for some discussion, maybe for some feedback from some people more experienced with Erlang, maybe just to give some new people a flavor of the language.

Interaction between processes, Concurrency

2) Write a function which starts N processes in a ring, and sends a message M times around all the processes in the ring. After the messages have been sent the processes should terminate gracefully.

-module(ring).
-export([start/2, loop/2]).
start(N, M) ->
    Seq = lists:seq(1, N),
    Messages = lists:reverse(lists:seq(0, M-1)),
    LastP = lists:foldl(fun(S, Pid) -> 
                                             spawn(?MODULE, loop, [N-S, Pid]) 
                             end, self(), Seq),
    spawn(fun() -> [ LastP ! R || R <- Messages ] end).
loop(N, NextPid) ->
    receive
        R when R > 0 -> 
            NextPid ! R,
            io:format(": Process: ~8w, Sequence#: ~w, Message#: ~w ..~n", 
                          [self(), N, R]),
            loop(N, NextPid);
        R when R =:= 0 ->
            NextPid ! R,
            io:format("* Process: ~8w, Sequence#: ~w, Message#: terminate!~n", 
                            [self(), N])
    end.

Explanation

Seq = lists:seq(1, N) and Messages = lists:reverse(lists:seq(0, M-1)),
These create lists of integers from 1 – N and then from M-1 – 0 (because of the reverse). These lists are used for creating processes and the messages that will be passed to those processes respectively.

LastP = lists:foldl(…
This is an accumulator function. The self() value passed to the function is passed in as Pid on the first iteration, but subsequent iterations get the value computed in the method with the spawn function. The final spawn Pid is returned from the accumulator and is stored in LastP. The spawn function is setting up new processes which are running the loop function with the given values.

spawn(fun() -> [ LastP ! R || R <- Messages ] end).
This is a list comprehension in Erlang. It basically takes each value from the Messages list and sends that as a message to the LastP pid which is the beginning of the Ring.

loop(N, NextPid) ->
This is the function that is being run as the processes of each of the elements of the ring.

R when R > 0 ->
When this process receives a message where the message is an integer greater than zero then write some info to the console and forward the message to the NextPid and use tail recursion to start waiting for another message.

R when R =:= 0 ->
When this process receives a message where the message is an integer that equals zero then write some info to the console and forward the message to the NextPid, but allow this process to complete naturally.

Erlang First Post

Some linguists and philosophers posit the idea that you can not have a thought for which you do not have language.

“The limits of my language mean the limits of my world.”
— Ludwig Wittgenstein

Erlang a bit. Erlang is a functional programming language that is very unlike the imperative languages which I, and many others, are most familiar. Learning a new programming language and especially a fundamentally new programming paradigm really changes the way you think about solving problems. If the linguists are to be believed, it fundamentally allows you to have no thoughts and ideas. This is what makes it so valuable for software developers to look at new languages. I thought I would share some tidbits.

Erlang Variables Aren’t Variable

Erlang only allows you to set the value of a “variable” once. If you try to set it more than once the language actually throws an error.


Eshell V5.6.2 (abort with ^G)
1> X = "foo".
"foo"
2> X = "bar".
** exception error: no match of right hand side value "bar"

At first this sounds like a huge limitation to my imperative mind. In many imperative it probably would be. In Erlang it ends up not being much of an issue. In many ways it’s one of the things that forces you do more idiomatic, functional Erlang.

Side Effect Free

Not being able to modify variables is one of the things that helps keep Erlang programs side effect free. Side Effects make programs harder to understand and can make them more error prone. A side effect free method is one that is “idempotent”, a fancy term that means every time you call it with a given value, it will return the same result.

Thinking of side effects and how they can be reduced or removed from imperative programs can make those programs easier to understand and test.

Pattern Matching as Polymorphism

To my imperative brain that grew up mostly on Object Oriented programming languages Polymorphism and related abstraction are notions of classes and types. Erlang changes this abstraction into one of Pattern Matching. Erlang’s pattern matching is almost a declarative construct like you would find in XSL. When you find call to a function that matches this pattern, use it, otherwise try the next function until you find one that matches.

To compute a Factorial, you can use 2 function signatures. The first *fac(0)* is called whenever the function is called with the integer value of zero. If the value is not zero, then that pattern is not matched and the next version is tried. In that case *fac(N)* where N is any value other than 0 is evaluated.

fac(0) ->
1;
fac(N) ->
N * fac(N-1).

In a slightly more complex example, you can actually pass a keyed Tuple. The key, in Erlang speak, is an atom, very similar to a Ruby symbol. Those atoms are used as part of the pattern matching to determine which function to execute.

area({square, Side}) ->
Side * Side;
area({circle, Radius}) ->
3.14 * Radius * Radius.


area({circle, 10}).
area({triangle, 2, 2, 2.82}). %% error, no match

Thinking about abstractions beyond types or classes in your Object Oriented programs could open you to some interesting new solutions

Distribution Should be Explicit, Not Necessarily Hard

Distributed computing takes more work than assuming all your code will be running on a singe machine, in the same process. The Fallacies of Distributed Computing are all about the assumptions we make when we try and hide the complexity of distribution from the caller. With Java and .NET, for example, remote calls can become so hidden that they look like just another method call within the local VM. While this is convenient, it also can lead to serious problems when users don’t take into account the overhead and the extra things that can go wrong with remote calls.

Erlang makes concurrent programming and spawning lots of processes to do work a very natural part of the language. Part of the language then is how to deal with the problems that arise when you run into issues talking to a remote process. The language has exception handling, it can be set up to receive a response, only wait for a timeout, etc.

The biggest thing that Erlang does is not try to hide the fact that you are communicating to a remote process (whether that process is in the same node, a different node, or a different machine). It gives you the programmer the tools to decide what conditions you need to handle based on how your program is built and deployed. All those scenarios are easy, but it’s still explicit that you are talking to a different process.


ping(N, PongPid) ->
PongPid ! {ping, self()},
receive
pong ->
io:format("ping received ~B~n", [N])
after 1000 ->
io:format("I don't think we're gonna get a response~n")
end,
ping(N - 1, PongPid).
pong() ->
receive
finished ->
io:format("pong finished~n", []);
{ping, PingPid} ->
io:format("pong received~n", []),
PingPid ! pong,
pong()
end.

Think about how you can make your distribution explicit and not hidden from callers who could make bad assumptions.

I’m finding Erlang and really trying to think in a functional programming language very interesting right now, so I’ll probably post some more about it. I think it will allow me to talk more intelligently to Grant at least.