Programming Erlang Book Club

My first contact with Erlang was about 2 years ago when I used RabbitMQ, which is written in Erlang, for my job. This made me curious and I started exploring the world of the BEAM, did some Elixir programming and used Phoenix for side projects.
Finally, the time has come to dig in deeper :slight_smile:

@AstonJ and I will be working our way through Programming Erlang and documenting our progress in this thread - please feel free to join us either by commenting on things you find interesting or by reading it with us! Weā€™d love the company! Weā€™ll try to writ something about each chapture.

Until now I just read the introduction and the ā€œIntroducing Concurrencyā€ part, which didnā€™t contain something particularly new to me, but it was a nice read for the start, and made me keen to work through the next chaptures :smiley:

7 Likes

Corresponding tweet for this thread:

Share link for this tweet.

1 Like

Whoo hoo! I canā€™t wait to read this book!

I had actually planned to read it after all of my Elixir/Phoenix books, however Iā€™ve been increasingly curious about the Erlang way and how it differs to the Elixir way. @DevotionGeoā€™s thread here reignited some of that curiosity and Robertā€™s posts in the thread then just pushed me to do it!

I also purchased the paper book which is not something I would normally do for a programming book (I prefer reading eBooks on my Kindle and they are of course more environmentally friendly) however I thought having a physical copy of the book might nice, like having a little bit of Joe here :blush:

Speaking of Joe, Like @Rainer Iā€™ve only read the first couple of chapters but I can tell you Joeā€™s personality shines through very strongly. If youā€™ve watched any of his talks or interviews, or interacted with him via the forums, twitter or email, itā€™ll feel like heā€™s there with you. At least thatā€™s how I feel given what Iā€™ve read so far.

So Iā€™m very excited to read this book and look forward to Rainerā€™s comments as well as any of yours should any of you join in or comment in the thread yourselves :nerd_face:

4 Likes

Iā€™m making my way through the second chapter, and Iā€™m writing down some things I should remember here. Concept wise still familar from elixir, itā€™s more the syntax that I need to get used to.

First: Commands are finished with a ā€˜.ā€™
Iā€™m used to ā€˜;ā€™, but a ā€˜.ā€™ makes sense, like finishing a sentence in spoken languages.

Variables begin with a capital letter, atoms with a small one, this needs attention while reading the code, itā€™s a bit more obvious in elixir where atoms start with a ā€˜:ā€™
What an atom is might be a bit strange at first for people coming from oop languages.

Recursions are optimized by the BEAM to Tail-Recursions, so the stack does not explode like in oop languages if writing recursion without thinking about it. A nice fact when talking to oop people when they say that recursion is evil :smiley:

3 Likes

Finished chapter 2 now with the exercise. Good read so far :wink:
@AstonJ how is your solution?

Hereā€™s mine:
Client:

put_file(Server, FileName, FileContent) ->
    Server ! {self(), {put_file, FileName, FileContent}},
    receive
        {Server, Response} -> Response
    end.

Server:

loop(Dir) ->
    receive
        {Client, list_dir} ->
            Client ! {self(), file:list_dir(Dir)};
        {Client, {get_file, File}} ->
            Full = filename:join(Dir, File),
            Client ! {self(), file:read_file(Full)};
        {Client, {put_file, FileName, FileContent}} ->
            Client ! {self(), file:write_file(FileName, FileContent)}
    end,
    loop(Dir).
4 Likes

I havenā€™t had time to read more yet :sob: I am hoping to tonight just before bed tho :smiley:

I will refer to your solution if I get stuck, haha!

1 Like

Finally managed to finish chapter 2 :nerd_face:

Hereā€™s my solution, which is essentially the same as yours :laughing:

-module(afile_client).
-export([ls/1, get_file/2, put_file/3]).

ls(Server) ->
  Server ! {self(), list_dir},
  receive 
    {Server, FileList} ->
      FileList
    end.

get_file(Server, File) ->
  Server ! {self(), {get_file, File}},
  receive
    {Server, Content} ->
      Content
    end.

put_file(Server, FileName, FileContent) ->
  Server ! {self(), {put_file, FileName, FileContent}},
  receive
    {Server, Content} ->
      Content
    end.
-module(afile_server).
-export([start/1, loop/1]).

start(Dir) -> spawn(afile_server, loop, [Dir]).

loop(Dir) ->
  receive
    {Client, list_dir} ->
      Client ! {self(), file:list_dir(Dir)};
    {Client, {get_file, File}} ->
      Full = filename:join(Dir, File),
      Client ! {self(), file:read_file(Full)};
    {Client, {put_file, FileName, FileContent}} ->
      Client ! {self(), file:write_file(FileName, FileContent)}
    end,
    loop(Dir).
1> c(afile_client).
{ok,afile_client}
2> c(afile_server).
{ok,afile_server}
3> FileServer = afile_server:start(".").
<0.104.0>
4> afile_client:get_file(FileServer, "afile_server.erl").
{ok,<<"-module(afile_server).\n-export([start/1, loop/1]).\n\nstart(Dir) -> spawn(afile_server, loop, [Dir]).\n\nloop(Di"...>>}
5> afile_client:put_file(FileServer, "new_file.erl", "Some content").
ok
6> afile_client:get_file(FileServer, "new_file.erl").                
{ok,<<"Some content">>}

Thoughts so far

Iā€™m loving this book!

I especially like how Joe is expressing whatā€™s what in Erlang in no uncertain terms and I like his analogies. The way he talks about Modules in Erlang being like classes in OOP (and that processes are like objects) and that processes are lightweight virtual machines - I donā€™t think Iā€™ve heard anyone else say that before.

Like @DevotionGeo I am also growing to like some of Erlangā€™s syntax, for instance I think atoms ( module/function names) being lowercase makes sense in a functional language because you use them a lot as you are forever calling some module:function(). I can also see why the . might have been used because it would be handy if youā€™re sending a lot of commands via a terminal, you could almost ā€˜talkā€™ to it by means of sending the commands as a series of sentences in a paragraph. However I am still unconvinced about it when writing everyday code in files.

I also like how he talks about there being a beautiful symmetry between the client and server - itā€™s just small things like this that help you see the thought behind things and it goes some way to shape the way you feel about things yourself too.

Canā€™t wait to read more! I bet you are flying ahead @Rainer!!

3 Likes

Not quite flying, just finished chapter 3 :wink:
Itā€™s about basic concepts, datatypes, the importance of immutability and pattern matching.
Still, nothing really new for me, but a nice read and fresh up anyway, giving a bit deeper insight :slight_smile:
For complete beginners maybe coming from oo only itā€™s already a lot of important information to understand :smiley: Especially the pattern matching, C# as an example has something they call pattern matching too, but itā€™s not even close to the real thing.

3 Likes

Iā€™ve finished chapter 3 too :nerd_face:

Like you, most of it feels familiar because of what Iā€™ve learnt with Elixir :smiley:

Iā€™ve been highlighting stuff as I go along too, and I plan to re-read the highlights every now and again to help reinforce stuff I think is important or just want to be reminded off.

1 Like

I finished reading chapter 4 now, itā€™s where the fun stuff begins, like higher-order functions and list comprehensions :smiley:
Always with good examples and step by step explanation, so itā€™s easy to follow.
I really like what Iā€™ve seen so far, and hope to find time to do the exercises soon :slight_smile:

As Iā€™ve seen, Robert Virding joined devtalk, thatā€™s cool :+1:

2 Likes

Ah yes, Robert has a knack for joining cool communities :sunglasses: (heā€™s been an Admin on the Elixir Forum since pretty much the beginning!). We also have Bjƶrn Gustavsson here too (member of the Erlang Core Team) as well as other famous Erlangers like Fred Hebert.

Unfortunately I havenā€™t had much time to read more, so what I think I might do is rather than just do one post per chapter, Iā€™ll post whenever I encounter something of interest too - thatā€™ll hopefully mean more frequent posts from me and mean you wonā€™t be as lonely in this thread, haha :blush:

With that in mind, I just posted a thread about something that cropped up in this book!

I am going to start saying unpacking moving forward, Joeā€™s exact words were: ā€œThen weā€™re going to unpack these data structures and extractā€¦ā€ :nerd_face:

Thereā€™s so much in this chapter Iā€™ve already highlighted and Iā€™ve only just started it!! Iā€™m really loving this book!

LOVE how easy it is to test right there in your module! (Loved this when I first saw it in Elixir too, but itā€™s even simpler in Erlang!)

LOVE how Joe explains the grammar: commas, semicolons, and periods.

Canā€™t wait to read more, and glad to see you are progressing well - the fact that you are is helping ensure I keep at it as I donā€™t want to fall too far behind, so thank you :+1:

1 Like

Thatā€™s good :slight_smile:

Iā€™d go with Joeā€™s word unpack, there canā€™t be something more correct than what he was using :stuck_out_tongue:

I started the exercise, bit didnā€™t get far.
Chapter 4, e1:
This one is quite straight forward, extend the geometry module that was created in the book:

area({rectangle, Width, Height}) -> Width * Height;
area({square, Side}) -> Side * Side;
area({circle, Radius}) -> 3.14159 * Radius * Radius;
area({righttriangle, A, B}) -> A * B / 2.

perimeter({rectangle, Width, Height}) -> (Width + Height) * 2;
perimeter({square, Side}) -> 4 * Side;
perimeter({circle, Radius}) -> 2 * Radius * 3.14159;
perimeter({righttriangle, A, B}) -> A + B + math:sqrt(A * A + B * B).

But the exercise 2 gave me some headaches, so Iā€™m very happy I had the idea for this solution :smiley:
Iā€™m curious with what youā€™ll come up :smiley:
Maybe we should have spoiler tags to cover the solutions, so you canā€™t see it ā€œaccidentallyā€ before you really want.
So donā€™t look at this before you did it by yourself, haha :stuck_out_tongue:

Click to reveal!
my_tuple_to_list(T) -> [element(X, T) || X <- lists:seq(1, tuple_size(T))].

Thatā€™s it for today, good night :night_with_stars:

2 Likes

We have spoiler tags here - when posting, just click on the cog icon and then > Hide Details to use it :smiley:

Iā€™ll hopefully get some time to read the book later - will let you know how I get on :nerd_face:

Gā€™night Rainer! :sleeping_bed: :sleeping:

1 Like

Ah thx, didnā€™t see that :slight_smile:

The solution of exercise 2 is very easy and quite obvious, but yesterday night it took some time to get the right thought :smiley:

2 Likes

Just one exercise today, as I was busy making a new floor in my office room :wink:

It looked simple first, but then youā€™ll find out that erlang:now/0 is deprecatedā€¦

Chapter 4 Exercise 3
-module(exercise).
-export([my_time_func/1]).

my_time_func(F) -> 
    Start = erlang:monotonic_time(),
    F(),
    End = erlang:monotonic_time(),
    erlang:convert_time_unit(End - Start, native, nanosecond).


exercise:my_time_func(fun() -> 3*4*5 end).  
3670
2 Likes

I didnā€™t get a chance to read any last night - for some reason I was really tired and slept for around 12 hours! Hope I havenā€™t picked up covid :scream: :mask:

Nice to see you are working through the exercises, hopefully I will get some time to read more tonight :smiley:

1 Like

12 hours sleep sounds very good, Iā€™m happy if I get 6 :roll_eyes:

I continued a little bit, but skipped exercise 4. 5 and 6 are quite straight forward:

Chapter 4 exercise 5
even(X) -> X rem 2 =:= 0.

odd(X) -> not even(X).
Chapter 4 exercise 6
filter(F, L) -> [X || X <- L, F(X)].

Not sure if I understood ex. 7. We should write the split/1 function twice, using accumulator and our own filter function, but with accumulator itā€™s the same as odds_and_evens2 in the book?
Using our filter function, it might be something like this:

Chapter 4 exercise 7
split(L) -> 
    Even = filter(fun(X) -> even(X) end, L),
    Odd = filter(fun(X) -> odd(X) end, L),
    {Even, Odd}.

(which we shouldnā€™t do as itā€™s processing the list twice)

Looking forward to your results :wink:

2 Likes

You should try to get at least 7 or 8 :stuck_out_tongue:

Unfortunately Iā€™ve not been able to get much further myself, tho I did learn something Iā€™ve never seen before! The test for equality in Erlang is with =:= :upside_down_face:

Hopefully Iā€™ll be able to catch up tonightā€¦

1 Like

Itā€™s not as if I donā€™t have the time to sleep 7-8 hours, itā€™s that i wake up in the middle of the night and canā€™t sleep again :zzz: Usually this is just short time when Iā€™m stressed, but the last weeks were not goodā€¦ However, now Iā€™m relaxing with Erlang at the evening :stuck_out_tongue:

I was also surprised when i saw the =:= for the first time :smiley:

I finished reading Chapter 5, no surprises here, but one good reminder: Donā€™t use too many atoms / dont allocate them dynamically. They are not carbage collected and at some point you risk a crash.

2 Likes

I wanted to do the exercises from chapter 5 this morning, the first is about loading a JSON file into a map.
The book states that there are BIFs for doing that (maps:from_json(Bin) -> Map), but all the shell has to say about that is:

** exception error: undefined function maps:from_json/1

A bit of googling reveals that there are no such BIFs, but some libraries to do this. I donā€™t really want to care about libs now, I think Iā€™ll skip this exerciseā€¦

Would be good if somehow this could be corrected in the book.

2 Likes