Pointing to immutability is not really a correct way to explain this. The behaviour doesn’t have much to do with immutability, but with how the lexical scoping in elixir works. Otherwise you’d need to argue that variable shadowing/rebinding shouldn’t work as well within the same scope. Immutability is mostly handled transparently for you unrelated to scoping rules.
The lexical scoping in elixir means variables assigned in outer scopes can be accessed within inner scopes, but variable assignment happens only for the current scope and does not leak to outer scopes. expressions, do/else/…
blocks as as well as anonymous functions are scope boundries.
def abc(conn) do # 1. parameter value assigned to conn in functions scope
IO.inspect(conn) # 2. conn (function scope) accessed while being in the scope of the function
conn = # 5. (re)assign conn (function scope) the value of the if expression
if is_active(conn) do # 3. conn (function scope) accessed while being in the scope of the if expression
# 4.a conn (function scope) accessed from :do block, assigned to conn in the do blocks scope
conn = assign(conn, :active, true)
conn # evaluate to value of conn (do block scope)
else
# 4.b conn (function scope) accessed from :else block, assigned to conn in the else blocks scope
conn = assign(conn, :active, true)
conn # evaluate to value of conn (else block scope)
end
conn # return value of conn (function scope)
end
Skipping step 5.
would return the unmodified conn as passed in to the function, given there was never a reassignment for conn
within the scope of the function.
The other part involved is that if/case/cond
are not statements like in many other languages, but also expressions. That means they evaluate to a value you can assign to a variable. Given the scoping rules explained above this is the only way to get values out of those expressions’ “bodies”.
All this for sure aligns with the immutability story, but it’s tech. not related. You can find lexical scoping in OO languages as well, though usually only around nested or anonymous functions.