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?