State in Elixir Again - Agents and Gen-server

I think I finally understand how and why Elixir handles state in an Agent or GenServer and I want the Elixir experts to chime in to see if I’m right, close to right, or dead wrong. I hope I’m right because if I’m not then I’m completely confused.

Basically Elixir sets up a recursive, tail optimized function which builds up state in its parameter(or a reference to the built up state) and this is the foundation on which the api’s Agent and GenServer sit on…

Also: This recursive, tail optimized function blocks while its waits for its queue/mailbox to receive messages that match clauses in its receive block.

So is this pretty close to the Elixir reality of state in Agents and GenServer?

2 Likes

Yes, this is the core concept. The basic idea can be expressed in very few lines of code really:

pid = spawn(fn -> loop(initial_state) end)

def loop(state) do
  next_state = receive do
    msg -> handle_msg(msg, state)
  end

  loop(next_state)
end

In fact, the actual erlang gen_server.erl code is generally quite readable and you can see the exact thing at work.

Here is our loop function https://github.com/erlang/otp/blob/maint/lib/stdlib/src/gen_server.erl#L367

It receives a message, then hands off to decode_msg which you can largely ignore, and decode_msg calls handle_msg: https://github.com/erlang/otp/blob/maint/lib/stdlib/src/gen_server.erl#L646

handle_msg has a number of different clauses but you’ll notice all the calls back to loop in there, and the circle is complete :slight_smile:

6 Likes

What an ingenious way to present state to the program… Now I understand all the fuss about processes and available state in an immutable Elixir environment. Thank-you.

3 Likes