Send With Confidence
Partner with the email service trusted by developers and marketers for time-savings, scalability, and delivery expertise.
Time to read: 5 minutes
I wrote an article a few months ago introducing you to Golang, and why I loved it so much. While I do indeed still love it, lately I’ve been playing around with a new language; Elixir. I bought the book Programming Elixir and have been following it through. I’ve already come to love Elixir and hope to show you why in this article.
Whilst I worked for Couchbase a couple of years back, I took a great interest in Erlang, and distributed systems. To me, Erlang is confusing. When I saw Elixir, I immediately knew I was onto something good. Elixir is detailed as a functional and concurrent language that runs atop of the Erlang VM.
I’ve heard a lot of times, people saying Elixir is ‘Ruby for Erlang’ etc. This theory isn’t fully incorrect, but realistically, it’s mainly just the syntax of Elixir that is influenced by Ruby, as it doesn’t share many of the same programming constructs. It is, of course, similar in ways to Erlang, with it being built atop of the Erlang VM, and giving us direct access to Erlang primitives natively.
Anyway, without further hesitation, let’s dive in and get on with some Elixir.
If you’re running on OSX, installation is as easy as using Homebrew: ~ brew update ~ brew install erlang ~ brew install elixir
Once you’ve done this, you should be able to run:
~ elixir -v > Elixir 1.0.2
Now Elixir is installed properly, we can open up an Interactive Elixir and play around with some basic common types.
Start up an Interactive Elixir REPL by entering > iex
iex(1)> name = "rbin" #=> "rbin"
In Elixir, an Atom is a constant in which it’s name is it’s own value. iex(2)> :this_is_an_atom #=> :this_is_an_atom iex(3)> :my_atom == :atom #=> false
We use the Curly Brace notation to define Tuples. In Elixir, Tuples are stored immediately in memory, meaning getting the size of a Tuple, or accessing a Tuple element is fast, but updating or adding elements is expensive as it requires copying the whole tuple in memory.
iex(4)> tuple = {:hello, "world"} #=> {:hello, "world"} iex(5)> elem(tuple, 1) #=> "world"
In Elixir, lists are stored in memory, as linked lists. We can update lists trivially by prepending elements, but appending elements is more expensive, as we need to traverse the whole list to figure it’s size.
iex(8)> list = [1, 2, :atom] #=> [1, 2, :atom] iex(9)> ["string"] ++ list #=> ["string", 1, 2, :atom] iex(10)> list ++ [31] #=> [1, 2, :atom, 31]
There are very useful in-built functions to be used with lists, including getting the Head & Tail of a list.
iex(11)> hd(list) #=> 1 iex(12)> tl(list) #=> [2, :atom]
In Elixir, functions are first-class citizens, meaning we can pass functions as arguments to other functions. Below, we'll define a variable named add which contains a function, that we will then pass as an argument to the is_function/1 func.
iex(14)> add = fn a, b -> a + b end #Function<12.90072148/2 in :erl_eval.expr/5>
iex(15)> add.(13, 31) #=> 44
iex(16)> is_function(add) #=> true
Elixir ships with a super useful tool named Mix. Mix is a build tool that allows us to very easily generate, organise, compile, and test our projects. It also makes it easy for us to manage dependencies. (Always a touchy subject!) To create a new project with Mix, we simply do the following: ~ mix new myapp --module MyApp
This will create a directory named myapp with a few files inside. It will also define a module MyApp inside lib/myapp.ex. * creating README.md * creating .gitignore * creating mix.exs * creating config * creating config/config.exs * creating lib * creating lib/myapp.ex * creating test * creating test/test_helper.exs * creating test/myapp_test.exs
Your mix project was created successfully. You can use mix to compile it, test it, and more:
cd myapp mix test
As we can see, we get all the files needed for a basic project structure. I think this is one of the nicer features available that ship with Elixir. Having project management tools is super useful and a big time-saver.
The file mix.exs is the main file used to configure our project, and manage dependencies etc. We get a test/folder, in which we can write very ruby-like tests for our project. We of course get a lib/folder, which contains the source files to our project. If we run mix test on our app, we get the following: $ mix test Compiled lib/myapp.ex Generated myapp.app .
Finished in 0.04 seconds (0.04s on load, 0.00s on tests) 1 tests, 0 failures
Randomized with seed 543313
Much like Erlang, Elixir uses the ‘Actor’ model for concurrency. All of our code runs inside Processes, and these processes are isolated from one another. We can make fully concurrent programs in Elixir by spawning Processes and sending and receiving messages between them.
In Elixir, we start processes by using the spawn function, which takes another function as an argument.
iex(1)> spawn(fn -> IO.puts 1 + 1 end) #=> 2 #PID<0.55.0>
As you can see, we spawned a process which outputted 1 + 1, and also returned it’s Process ID. Returning this Process ID is useful, as we can assign it to a variable, and use it to send messages to the process. Before we do that, we need to create a receive mechanism to attain the messages we send to the process. (We can go ahead and do this in our Interactive Elixir session, line by line.)
pid = spawn(fn -> Geometry.area_loop() end)
#=> #PID<0.40.0>
send pid, {:rectangle, 2, 3}
#=> Area = 6
# {:rectangle,2,3}
send pid, {:circle, 2}
#=> Area = 12.56000000000000049738
# {:circle,2}
Process.alive?(pid)
#=> false
Partner with the email service trusted by developers and marketers for time-savings, scalability, and delivery expertise.