This year, I spent some time with Erlang by building a tuple space with it (a particular kind of distributed data structure oriented to concurrency). Although not as fashionable as some time ago, the language is itself interesting and I want to deepen my understanding of it.
For this reason, I am starting a new series where I will regularly post about Erlang. My articles will have an high content of code and I will follow as textbooks O'Reilly's book Erlang Programming by Francesco Cesarini and Simon Thompson, and Programming Erlang: Software for a Concurrent World by language's author Joe Armstrong.
The hidden motive of studying Erlang is not only his patterns for concurrency and fault tolerance - which are different from classic imperative programming ones; not even its functional approach, which you can learn about with a modern version of Lisp. It's the notion that Erlang processes force you to take a radical object-oriented approach, where each process is an object and the isolation between processes is maximum.
Erlang might be the only object oriented language -- Joe ArmstrongBut we'll talk about this later - let's start from the basics.
Erlang is a compiled language, but setting up a build immediately is only going to slow us down. We will be able to play for a bit with the language by using the bundled interpreter escript.
First, install the Erlang interpreter with:
sudo apt-get install erlang-base
or look for the package that provides escript if you're using a non-Debian distribution or another OS.
This is an Hello World script:
#!/usr/bin/env escript main(_) -> io:format("Hello, world!\n").
You can run it by executing:
gedit 01_helloworld.erl # paste the file contents chmod +x 01_helloworld.erl ./01_helloworld.erl
The output will be:
$ ./01_helloworld.erl Hello, world!
How does it work?
There's already a lot going on here: let's delve into what we did.
We defined a single Erlang function, which by convention has the signature main/1 to be called by escript (just like the main function in C or Java). By main/1 I mean a function named main that takes a single argument; since there is no type definition forced on the arguments overloading only takes place with different number of arguments (but pattern matching means you won't miss it.) main/1 and main/0 or main/2 are totally different functions.
An Erlang function, when containing a single case, consist of a list of actions. In this case we have only one action:
which is a call to the format/1 function inside the *io* module. If we take a look at this function's documentation we see:
format(Format) -> ok
which means Format is the argument that will be printed to the console and ok is the return value. But why the uppercase and lowercase difference?
Atoms and variables
A little session in the Erlang shell will clear this up. Variables always start with an uppercase letter:
$ erl Erlang R14B04 (erts-5.8.5) [source] [64-bit] [smp:2:2] [rq:2] [async-threads:0] [kernel-poll:false] Eshell V5.8.5 (abort with ^G) 1> Format = "Hello, world!\n". "Hello, world!\n"
The Erlang REPL is printing the value of the last expression as an aid for us: we aren't actually explicitly printing anything by defining a variable.
While strings are useful, we also have integers, and many other types:
2> SomeInteger = 42. 42
One of this types is the atom, a diffused idiom in functional languages. You can think of it as an evolution of enums, with the difference that there is no limit on the atoms you can use. An atom is a constant value used for matching and equality comparisons; it starts with a lowercase letter to distinguish it from a variable.
3> ok. ok
Since an atom is a value just like "Hello" and 42, we can assign it to variables.
4> AnAtom = ok. ok 5> AnAtom. ok
If we print everything, the atom is converted to a string for our convenience.
6> io:format(Format). Hello, world! ok 7> io:format(AnAtom). okok
In the last case, we printed ok as the conversion of the atom and then the shell printed ok again as the return value of io:format/1. The same goes for the first call.
Finally, let's check we are in a real functional language. Variables are immutable:
8> SomeInteger = 23. ** exception error: no match of right hand side value 23
This cryptic error means that we're trying to match a bounded variable (SomeInteger) with the value 23, which is different. Thus, the comparison fails; if you try to assign 42 again however:
9> SomeInteger = 42. 42
The values match and 42 is returned (for further assignment, for example).
starting from the Hello World of today.
If you want to have a feeling of Erlang, experiment with the erl shell or with the escript interpreter. Next time we're going to solve our first toy problem with Erlang functions.