Here is an edited version of Stack sample I see on https://blog.codeship.com/statefulness-in-elixir/ (by Micah Woods). It works by the way.
defmodule Stack do
def start_link do
pid = spawn_link(__MODULE__, :loop, [[]])
{:ok, pid}
end
def loop(stack) do
receive do
{:size, sender} ->
send(sender, {:ok, Enum.count(stack)})
{:push, item} -> stack = [item | stack]
{:pop, sender} ->
[item | stack] = stack
send(sender, {:ok, item})
end
loop(stack)
end
end
Inside the loop() function, the stack variable is rebound in some cases in the receive block, but not others. This seems to be the behavior of a mutable variable, not a variable rebinding.
In my mind, variable rebinding should only be allowed if there is clear delineation between old and new variable. i.e. only if the code can be rewritten without variable rebinding. In a language without variable rebinding, the loop() code would look like this:
def loop(stack) do
receive do
{:size, sender} ->
send(sender, {:ok, Enum.count(stack)})
###### stack2 not defined in this case ######
{:push, item} -> stack2 = [item | stack]
{:pop, sender} ->
[item | stack2] = stack
send(sender, {:ok, item})
end
loop(stack2)
end
Notice stack2 is not defined in the first case. So is stack2 assigned the value of stack by default if no assignment occurs, or stack is actually a mutable variable under the hood?
So how do I understand this rebinding concept in Elixir properly and logically? In my mind this is encroaching on the mutable variable territory. How does the rebinding work under the hood?
This is just a rebind of the variable. There is nothing mutable happening here.
It is a mis-feature of Elixir that has been deprecated. If you try to compile this, you will receive a warning telling you that the variable is unsafe. This should be fully removed soon. Unfortunately, I do not know exactly when.