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?
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)
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
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
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.