I'm currently studying Elixir and I'm reading "Functional Web Development with Elixir, OTP and Phoenix", which imo is a great book. Working at the state machine chapter, I came up with the following code:
defmodule IslandsEngine.Rules do
alias __MODULE__
defstruct state: :initialized
def new(), do: %Rules{}
def check(%Rules{state: :initialized} = rules, :add_player), do:
{:ok, %Rules{rules | state: :players_set}}
def check(_state, _action), do: :error
end
The code above should work as a fully functional state machine. I'll paste above a few of iex commands:
iex(1)> alias IslandsEngine.Rules
IslandsEngine.Rules
iex(2)> rules = Rules.new()
%IslandsEngine.Rules{state: :initialized}
iex(3)> {:ok, rules} = Rules.check(rules, :add_player)
{:ok, %IslandsEngine.Rules{state: :players_set}}
iex(4)> rules.state
:players_set
So as you can see, the state struct has changed from :initialized
to :add_player
. Great.
My question is: is state:
struct really immutable? I mean, the method check/1
returns a copy of the struct with a state: :players_set
statement, which follows a correct functional pattern... but how does it "overwrite" the current status without modifying it directly?
Thanks a lot!
Elixir data-structures are indeed immutable. But what happens is that function calls return a completely new value (that is different from the original depending on the function you called).
As for the "changing the variable's value", that's an added feature in
Elixir
(over the originalErlang
language). The variable's value doesn't actually change, it's just rebinded to the new one. The old ones are automatically garbage collected by theErlang VM.
So in your example: