The other day I received an email from a friend who is coming to Elixir from Ruby. The subject line was “elixir immutability”.

The question

I’m working throughout the elixir-lang.org tutorial and I cannot understand why the language is immutable AND I can keep re-assigning the different values to the same variable

iex(21)> x = 1
 1
 iex(22)> x = 2
 2
 iex(23)> x
 2

I thought the definition of immutability is that you can’t do that! What gives?

My response

Variables in Elixir are immutable like they are in Erlang. The thing you are seeing that looks like mutation (and drives many Erlangers crazy) is called rebinding (more here). So in your shell example, you didn’t actually change the value that x pointed to. Instead, you created a brand new identifier with the name x that pointed at a different value (2). The old identifier x is no longer available, but its old value (1) remains in memory untouched until it is garbage collected. The following sample uses an anonymous function to show what’s happening a bit more clearly:

iex(1)> x = fn () -> "First one" end
#Function<2.90072148/0 in :erl_eval.expr/5>
iex(2)> z = x
#Function<2.90072148/0 in :erl_eval.expr/5>
iex(3)> x = fn () -> "Second one" end
#Function<2.90072148/0 in :erl_eval.expr/5>
iex(4)> x.()
"Second one"
iex(5)> z.()
"First one"
iex(6)>

I’m not a fan of rebinding, but under the hood, Elixir plays by the same rules as Erlang. It may put you at ease to know that the Elixir compiler is taking your x = 1,x = 2 and mapping them to identifiers that do not clash such as x1 = 1 and x2 = 2 before it all goes to byte code.

Elixir’s rebinding doesn’t create any of the shared-mutable-memory concurrency problems of non-functional languages. I suppose José Valim felt the syntactic sugar of rebinding would make people feel more at home if they were coming from OO languages.”

The reply

And that explanation explains it perfectly. If you blog elixir, consider posting that because I didn’t “get it” from googling for it.

Done!

Well not quite…

I feel I need to go into why rebinding drives many Erlangers crazy, but first let’s start with how Erlang drives everyone else crazy. Rebinding was introduced in Elixir to avoid an ugly thing that happens in Erlang code when you need to perform a series of operations on some data. For example a dictionary in Erlang…

Eshell V6.3  (abort with ^G)
1> X = dict:new().
{dict, ...
2> X1 = dict:append("A",1,X).
{dict, ...
3> X2 = dict:append("B",2,X1).
{dict, ...
4> X3 = dict:append("C",3,X2).
{dict, ...
5>

Yes, the intermediate variables X,X1,X2,X3 are pretty darn ugly. It’s not just ugly; it’s potentially dangerous. Several times in Erlang, I’ve accidentally passed the wrong intermediate variable to a dict and as a result “lost a step” in the transformation. Unless you make an unfortunate combination of multiple goofs, you will get a compiler warning saying you have “unused variables”. That compiler warning often saves the day. At any rate, everyone agrees this code is ugly.

Now back to Elixir. Elixir’s rebinding allows something more “normal looking” (to a non-FP developer anyway).

iex(1)> x = HashDict.new
#HashDict<[]>
iex(2)> x = Dict.put(x, "A", 1)
#HashDict<[{"A", 1}]>
iex(3)> x = Dict.put(x, "B", 2)
#HashDict<[{"A", 1}, {"B", 2}]>
iex(4)> x = Dict.put(x, "C", 3)
#HashDict<[{"A", 1}, {"B", 2}, {"C", 3}]>
iex(5)>

There we only have to keep up with one variable x. While not as ugly, this code is still pretty ugly, and there is a better way. Elixir’s lovely pipe-forward operator (|>) produces a much more elegant solution:

iex(1)> x = HashDict.new |>
...(1)> Dict.put("A", 1) |>
...(1)> Dict.put("B", 2) |>
...(1)> Dict.put("C", 3)
#HashDict<[{"A", 1}, {"B", 2}, {"C", 3}]>
iex(2)>

The |> says: “take the output of the expression to the left and push it in as the first argument to the expression on the right”. This feels functional; this makes me happy. With the pipe operator, I don’t need/want the ability to rebind x to different values.

The harm for Erlangers

Ok, but where is the actual harm in rebinding? The thing that drives Erlangers crazy is not aesthetics (obviously)…(rimshot)…(cheapshot).

Say we are Harry from the Harry Potter series. Ron Weasley is our buddy, and Voldemort will kill us on sight. We decide to code up a safety charm for our front door. We select Elixir and the ErlangVM because it is functional, declarative, and reliable. Here we go…

iex(1)> friend = "Ron Weasley"
"Ron Weasley"
iex(2)> enemy = "Voldemort"
"Voldemort"
iex(3)> knocking_at_our_door = "Voldemort"
"Voldemort"

Yes, Ron is our friend and Voldemort is our enemy, and you-know-who is about to knock at our door. Our case statement should welcome our friend (i.e. “Ron Weasley”) and curse/disarm our enemy (i.e. “Voldemort”).

iex(4)> our_response = case knocking_at_our_door do
...(4)>   friend -> "Come on inside, #{friend}."
...(4)>   enemy -> "Expelliarmus!"
...(4)> end
"Come on inside, Voldemort."

Wait! What the hell just happened?! Voldemort knocked at our door, and we say, “Come on inside, Voldemort.” Let’s check our variables (and our underpants) to see what just happened…

iex(5)> friend
"Ron Weasley"
iex(6)> enemy
"Voldemort"
iex(7)> knocking_at_our_door
"Voldemort"
iex(8)> our_response
"Come on inside, Voldemort."

This is crazy. And we are dead. If we had written the following code instead, Harry Potter would have lived.

iex(4)> our_response = case knocking_at_our_door do
...(4)>   ^friend -> "Come on inside, #{friend}."
...(4)>   ^enemy -> "Expelliarmus!"
...(4)> end
"Explelliarmus!"

See the difference? Notice the ^friend versus friend and ^enemy versus enemy. The hat ^ says “use the last pinned value of this variable.” Without the ^ the variable friend wasn’t used as a guarding, declarative pattern match; instead it was used as a short-lived re-bound variable that held whatever was passed in. That first clause would always match no matter what was passed in, and as soon as the case statement fell out of scope the only evidence that friend was ever equal to Voldemort is our_response. That is subtle; that is dark magic. It is easy (especially for Erlangers who expect a match) to miss it. This will cause problems, and the upside is hard to see.

Another question: if we write this as a module, will the compiler save us with a helpful warning? Answer: maybe, or maybe not.

defmodule KnockKnock do 
  def who_is_there do
    friend = "Ron Weasley"
    enemy = "Voldemort"
    knocking_at_our_door = "Voldemort"

    our_response = case knocking_at_our_door do
      friend -> "Come on inside, #{friend}."
      enemy -> "Expelliarmus!"
    end

    {friend,enemy,knocking_at_our_door,our_response}
  end
end

…and we compile

iex(1)> c "knock_knock.ex"
knock_knock.ex:9: warning: variable enemy is unused
[KnockKnock]

Hmm… Mixed bag. There is no warning about friend because we (pure-dumb-bad-luck) happened to use the value in our response. We do get a compiler warning on line:9 because enemy is not used in that clause (pure-dumb-good-luck). That might have been enough to clue us in to the bug. If not, when we run…

iex(2)> KnockKnock.who_is_there
{"Ron Weasley", "Voldemort", "Voldemort", "Come on inside, Voldemort."}
iex(3)>

Knock, knock. Who’s there? You know. You-know-who?

Conclusion

Identifier rebinding is not harmful in the same way that mutable variables are harmful. It’s not going to jack up your parallel work. Rebinding does create a potential pitfall though, and it adds a diligence requirement (always a bad thing) when using pattern matching.

This is an ugly wart on a beautiful language. Fortunately, there is a solution that is well proven, and it doesn’t require Elixir to beak its v1.0 contracts. In Erlang, if you write a case in which a pattern will never match you get a warning

Warning: this clause cannot match because a previous clause at line 11
always matches

If Elixir were to do the same everyone wins (except Voldemort).

Pretty excited about yesterday’s release of Erlang/OTP 17.0. You can read more about why this release is important from Joe Armstrong’s February 1 post: “Big Changes to Erlang“. The release of Erlang/OTP 17 is important to the v1.0 release of Elixir as well: “Milestones for 1.0“.

Getting it:

The good folks at Erlang Solutions publish and maintain a library of prebuilt Erlang packages for many platforms here.

If you are on Linux or Mac many folks use a handy tool named Kerl to build and switch between multiple releases of Erlang. Get started here: https://github.com/spawngrid/kerl.

If you are on Windows you’ve got it easy. Go to the Erlang.org’s download page (here) and download the 32-bit or 64-bit OTP 17.0 Windows Binary File. It runs as a standard Windows installer, and it works great. All dependencies are pulled in for you including wxWidgets which is used with the graphical tools Debugger and Observer.

Finally, if you are on Ubuntu and want to see how to build from source (and get the required dependencies) I have a Gist that will help you “Build Erlang 17.0 on a fresh Ubuntu box (tested on 12.04)

#!/bin/bash
# Pull this file down, make it executable and run it with sudo
# wget https://gist.githubusercontent.com/bryanhunter/10380945/raw/build-erlang-17.0.sh
# chmod u+x build-erlang-17.0.sh
# sudo ./build-erlang-17.0.sh

if [ $(id -u) != "0" ]; then
echo "You must be the superuser to run this script" >&2
exit 1
fi
apt-get update

# Install the build tools (dpkg-dev g++ gcc libc6-dev make)
apt-get -y install build-essential

# automatic configure script builder (debianutils m4 perl)
apt-get -y install autoconf

# Needed for HiPE (native code) support, but already installed by autoconf
# apt-get -y install m4

# Needed for terminal handling (libc-dev libncurses5 libtinfo-dev libtinfo5 ncurses-bin)
apt-get -y install libncurses5-dev

# For building with wxWidgets
apt-get -y install libwxgtk2.8-dev libgl1-mesa-dev libglu1-mesa-dev libpng3

# For building ssl (libssh-4 libssl-dev zlib1g-dev)
apt-get -y install libssh-dev

# ODBC support (libltdl3-dev odbcinst1debian2 unixodbc)
apt-get -y install unixodbc-dev
mkdir -p ~/code/erlang
cd ~/code/erlang

if [ -e otp_src_17.0.tar.gz ]; then
echo "Good! 'otp_src_17.0.tar.gz' already exists. Skipping download."
else
wget http://www.erlang.org/download/otp_src_17.0.tar.gz
fi
tar -xvzf otp_src_17.0.tar.gz
chmod -R 777 otp_src_17.0
cd otp_src_17.0
./configure
make
make install
exit 0

Here’s an introduction to distribution in Erlang. This screencast demonstrates creating three Erlang nodes on a Windows box and one on a Linux box and then connecting them using the one-liner “net_adm:ping” to form a mighty compute cluster.

Topics covered:

  • Using erl to start an Erlang node (an instance of the Erlang runtime system).
  • How to use net_adm:ping to connect four Erlang nodes (three on Windows, one on Linux).
  • Using rpc:call to RickRoll a Linux box from an Erlang node running on a Windows box.
  • Using nl to load (deploy) a module from one node to all connected nodes.

For a deeper dive into distributed Erlang here’s the official reference.

Introduction to Distributed Erlang from Bryan Hunter on Vimeo.

In 2007 when I keyed my first “HelloWorld.erl” in Notepad, I remember a general uneasiness descending over me.

I’m typing code in Notepad.
Notepad doesn’t have syntax highlighting.
Notepad doesn’t provide error squiggles.
Notepad doesn’t provide IntelliSense.
Notepad doesn’t have a “Build Solution”.
How am I supposed to set a breakpoint from Notepad?
How am I supposed to debug this stuff?
Oh, dark night of the soul! What am I getting into here!?

Well here’s an answer to at least the debugging bit…

This screencast is a simple demo of debugging (stepping through) a recursive function in an Erlang module. For grins, and to make it clear that no IDE magic is involved, the code is edited using Notepad.

Debugging in Erlang from Bryan Hunter on Vimeo.