From Ruby to Elixir, Initial Thoughts on the Basics and Getting Started (pt. 1)
By: Brad Mccollum
Tags: Ruby, Object Oriented, Elixir, Learning, Functional Programming

For the last year I’ve almost been exclusively using Ruby on Rails, JavaScript and the React/Redux libraries. As much as I love Ruby, I wanted to try something else to expand my horizons, broaden my skillset, and ultimately round myself out as a developer. I’ve always defaulted to object oriented programming, and lately I’ve been hearing a lot about the benefits of functional programming, especially with Elixir and Phoenix. Oft compared to Ruby on Rails, Elixir/Phoenix have much in the way to offer when it comes to subjects like concurrency, performance, scalability, and more. Recently, I finally decided to pick up some materials recommended to me and started to learn. So far I’m loving what I see, and I want to document my learning process and thoughts along the way, which is what this post will be the start of. Since I’ve never programmed in a truly functional style before, I’m going to be flying through some of the basics to understand how Elixir differs from Ruby and OOP from FP. With that said, we’ll go ahead and jump right into i! Today I wanted to focus on some initial thoughts about Elixir and its tools, especially as compared to Ruby, and cover some of the basics that I’ve been learning about.

One of the first things I learned about that put a big ol’ smile on my face was the presence of IEx, also known as Interactive Elixir (shell). If you’re familiar with Ruby at all, chances are you know about IRB, or Interactive Ruby (shell). Essentially these both allow you to simulate your environment, allowing you to play around with your code, or just test some things out. They are also incredibly helpful when it comes to debugging, allowing you to essentially insert breakpoints in your code that then break into the shell and allow you to manipulate data in a simulated environment. Pry has binding.pry and Elixir has IEX.pry . In my book this instantly gave Elixir some bonus points! Unlike IRB, IEx requires a few additional steps to get started with your code. Assuming you have Elixir fully installed, all you need to do to get started is type iex in your command line and boom you’re in. Right off the bat it’s going to feel very similar to IRB and you can do many of the same things. Before we get started, I want to mention that it would behoove you to check out IEx’s help call, which is super handy. You can access help simply by typing ‘h’. Even more handy though is checkout out what functions are available to a specific module. In order to this just type the name of the module, followed by a period, and hit tab:

iex(2)> String.

Break Casing Chars

Tokenizer Unicode at/2

bag_distance/2 capitalize/1 capitalize/2

chunk/2 codepoints/1 contains?/2

downcase/1 downcase/2 duplicate/2

ends_with?/2 equivalent?/2 first/1

graphemes/1 jaro_distance/2 last/1

length/1 match?/2 myers_difference/2

next_codepoint/1 next_grapheme/1 next_grapheme_size/1

normalize/2 pad_leading/2 pad_leading/3

pad_trailing/2 pad_trailing/3 printable?/1

printable?/2 replace/3 replace/4

replace_leading/3 replace_prefix/3 replace_suffix/3

replace_trailing/3 reverse/1 slice/2

slice/3 split/1 split/2

split/3 split_at/2 splitter/2

splitter/3 starts_with?/2 to_atom/1

to_charlist/1 to_existing_atom/1 to_float/1

to_integer/1 to_integer/2 trim/1

trim/2 trim_leading/1 trim_leading/2

trim_trailing/1 trim_trailing/2 upcase/1

upcase/2 valid?/1

iex(2)> String.

These are all of the functions available to the String module. If you curious about why a lot of these functions have a forward slash and a number next to them, well that is because it’s the number of arguments that the function takes, and Elixir considers each variant a different function. You can get more information by finishing the rest of the name and hitting enter. Let’s check out upcase/2:

iex(3)> h String.upcase/2 def upcase(string, mode \\ :default) @spec upcase(t(), :default | :ascii | :greek) :: t() Converts all characters in the given string to uppercase according to mode. mode may be :default, :ascii or :greek. The :default mode considers all

non-conditional transformations outlined in the Unicode standard. :ascii

uppercases only the letters a to z. :greek includes the context sensitive

mappings found in Greek. ## Examples iex> String.upcase("abcd")

"ABCD" iex> String.upcase("ab 123 xpto")

"AB 123 XPTO" iex> String.upcase("olá")

"OLÁ" The :ascii mode ignores Unicode characters and provides a more performant

implementation when you know the string contains only ASCII characters: iex> String.upcase("olá", :ascii)

"OLá"

Pretty handy right? IEx does a really great job of making this information available and easy to digest. I encourage you to play with this some more, but maybe after you’re done reading this :). Let’s move into using IEx and we’ll start by just experimenting with a few simple lines:

iex(1)> IO.puts “hello world!”

hello world!

:ok

iex(2)> “hello world”

“hello world”

iex(3)> 1 * 3

3

iex(4)> 3 * 3 * 3

27

You may be curious as to why each line is numbered. Well glad we’re on the same page! This is another nifty feature of IEx. You can essentially recall the output of any line by typing v <line #> and even manipulate that result as well! Take a look:

iex(1)> 1 * 3

3

iex(2)> 2 * 4 * 6

48

iex(3)> v 1

3

iex(4)> (v 1) * 3

9

Or we could do something silly like use it to concatenate two strings using the <> operator which does just that:

iex(1)> "hello"

"hello"

iex(2)> "world"

"world"

iex(3)> (v 1) <> " " <> (v 2)

"hello world"

Moving on; if you’re playing around in IEx to test out some modules/functions, you will have to compile that, which does not happen automatically if you just start iex in the normal manner. In order to have access to your modules from IEx you’ll need to start IEx by calling iex -S mix (yes the ‘S’ does need to be capitalized). In that same vein, if you make changes to your code while you have an IEx session open, you’ll have to recompile it to be able to access those changes. If we are just testing a specific module, we can do this by calling r <ModuleName> . In order to compile a specific file, we could instead do c(files, path \\ :in_memory) . Let’s see how testing a specific function works. For this example, we have the spectacularly bland file named ‘test.ex’ inside of our lib directory. Inside of test.ex we have the following module and function:

defmodule Test do def say_hi(name), do: "Hello there #{name}, it's nice to meet you!" end

You’re probably thinking, “Hey! This looks pretty similar to Ruby!” and you’re not wrong. It does have a very similar feel in some regards, although it certainly has its differences. In this example, Test is our module and the say_hi/1 function lives inside it. Let’s go ahead and start up IEx by running iex -S mix . Everything has been compiled and we are ready to rock. In order to invoke the say_hi function we need to access it as a function of Test by doing the following:

iex(1)> Test.say_hi("Brad")

"Hello there Brad, it's nice to meet you!"

You’ve just written and invoked your first Elixir module and function, great job! Before we do anything more advance than working with strings or integer we should probably talk about a few differences Elixir has from Ruby when it comes to typing and what you’re used to using. One of the biggest changes, in my opinion at least, is that Elixir does not have access to arrays or dynamic arrays (arrays in Ruby). Instead you’ll be using lists, as in linked lists, which are represented like an array but they are A LOT more convenient to work with in Elixir than you’re probably imagining. On top of lists, these are the basic types you’ll be dealing with in Elixir:

iex> 1 # integer iex> 2.0 # float iex> true # boolean iex> :atom # atom (symbol) iex> "hello world" # string iex> [1, 2, 3] # list iex> {1, 2, 3} # tuple

Most of these should be pretty familiar to you but just a couple of quick notes. When it comes to truthy-ness, everything in Elixir is truthy other than false and nil. An atom is basically a symbol. A tuple may sound foreign but is essentially the same thing as a Hash in Ruby and works largely the same way. Another large change (the most obvious) is that you’re no longer dealing with objects. Since everything is essentially an object in Ruby, you have access methods directly on the data you’re manipulating. If we want to know the length of a string, we can simply do something like “hellllllllooooooooo world!”.length . Remember, this is not an object oriented language and we are not dealing with objects here, so we cannot call methods in the same manner on our data. In an OO language that object is a blueprint, and here we are essentially dealing with straight data. Instead, we will need to access a modules functions. In order to get the length of this string in Elixir we’d call String.length(“hellllllllooooooooo world!”) which is invoking the length function of the String module. It takes a bit of getting used to, but I did not find it too difficult to flip that mental switch and it’s a pretty interesting change from what I’m used to.