In BlogPost, Elixir

The Ultimate Guide for Making the Jump to Elixir

Learn The Basics So You Can Write Production Ready Code

Bruce Park

Contents

Preface

Learning in layers…

I started out with Ruby. When Elixir came out I took a peek and was interested. Slowly, I began to make time for it with my Ruby day job. Eventually, I transitioned out of my Ruby job and found an Elixir one.

This prediction might be completely wrong, but I think Elixir is the future.

Either way, I hope you enjoy the book and please don’t hesitate to contact me with any questions or any issue at all at [email protected]

Last Updated: 04/09/2018 Monday

If you’re new to Elixir and have been wanting to learn it quickly, check out the Elixir Core Video course (now at special Beta launch pricing). In just 30 minutes a day, you can teach yourself the fundamentals of Elixir. Click on the image below to enroll today!

Chapter 1 Introduction

You’ve got a full time day job working in an object-oriented language like Ruby, Java, or C++ but you’ve been wanting to come up to speed on Elixir. If you’ve got a family or other pressing commitments, taking hours out of your week to read blog posts or spending time to contribute to open source could be a deal breaker for you.

1.1 How I Transitioned to Elixir

I got started in Elixir by doing simple code katas and doing some minor open source contributions. Then I somehow found a day job in Elixir, mostly doing web application development type work. So having been through hours of blog posts and reading different books, I’ve started distilling it down into the most efficient pathway to go from an object-oriented language to Elixir.

1.2 Elixir is rising

But perhaps you’re interested in functional programming and you can see that Elixir is rising. Plus, the advantages it has for solving certain classes of problems really appeals to you. So that’s why I created this course. No, I’m not promising you can go through it in “30 days” and become an Elixir expert. But I am confident you will get the tools you need to understand the basics of the language, avoid the hours of pitfalls I had while learning the language coming from an object-oriented background in Ruby, and get you on your way.

I’m also confident if you spend 30 minutes a day going over this stuff, you can do it rather quickly. Certaintly, you can do it more quickly than by spending hours reading random blog posts and books.

1.3 Welcome

So welcome aboard. Don’t hesitate to ask me questions as you go through the course and I hope you enjoy it!

May the 1’s and 0’s be with you,

Bruce Park

2.1 The Power of Proper Tooling

As I began to acquire more expertise and experience in programming, I realized that in some ways, 50% of the battle in getting started with learning a new technology stack is getting setup with the right tooling.

I still remember the first time I setup a shortcut for setting up git status. I added a shortcut with git st. One of my coworkers showed me a shortcut gs – even shorter! Holy cow, what a difference having not to type those last few characters makes!

2.1.1 And that’s the power of proper tooling

Proper tooling makes you more productive and makes programming more fun. I find having a proper environment manager to help you manage different releases of a language, makes it easy to test out different versions of the language. This especially holds true for an up and coming language like Elixir. So let’s dive into the tools!

2.1.2 Overview of The Tools

Let’s go over some tools you can use to manage your Elixir (and Erlang) installation. Since Elixir runs on top of Erlang, you’ll want a way to easily manage both Elixir and Erlang installations. Hopefully by the end of this, you’ll have everything setup and be ready to dive into the wonderful world of Elixir.

Kiex

If you’ve used a Ruby version manager like RVM or chruby, then you can think of kiex as being equivalent to that. Kiex is a handy little tool to let you easily install and/or switch between Elixir versions. And as Elixir is a fairly new language, it’s constantly being updated.

Kerl

Kerl is the tool that lets you easily switch out and build different Erlang versions. It’s a pretty handy tool to have since newer versions of Elixir keep using newer versions of Erlang. For example, due to some recent changes in the way Elixir handles debugging messages, Elixir 1.5 lets you take advantage of this functionality but only if you have Erlang 20 installed (at the time of this writing).

asdf

I would be somewhat remiss if I didn’t mention asdf, as it is a pretty handy tool that lets you install more than just Elixir. Asdf is “an extendable version manager” and it supports Erlang, Elixir, Ruby, and more languages. In my experience you end up with a .tool-versions file in your code repositories where you’re using the tool.

But that’s a minor thing in my opinion. Overall, if I hadn’t done kiex and kerl, I might have gone with asdf. The point is, “you do you”. Pick what is most comfortable to you.

2.1.3 Option 1: Installing Elixir with Kiex and Kerl

I’m going to give you a step-by-step overview of how to install Elixir with kiex and kerl.

If you’re used to using Ruby in your day job, you’ve probably come to appreciate the Ruby ecosystem of tools to get setup and running – bundler and rvm (or chruby or rbenv depending on your preferences).

2.1.4 But I’m used to RVM and other environment managers – where is the RVM for Elixir?

It turns out there’s a few options for Elixir. As I stated before, I ended up choosing Kerl and Kiex. Here is how I installed it on my Ubuntu desktop and Mac OSX laptop.

Step 1 – Installing Kiex

Kiex is like RVM in that it allows you to switch between different Elixir versions and build them. Below is a set of instructions you enter at the command line.

Step 2 – Installing Kerl, Elixir and Erlang

Because Elixir runs on top of Erlang, you need a way to build and install Erlang/OTP instances.

Below is a set of instructions you enter at the command line.

You can activate this installation running the following command:

In .bashrc (or .zshrc if you use z shell), add the following:

Later on, you can leave the installation by typing: kerl_deactivate

You can delete a build with kerl delete build 20.0.

Source: https://github.com/yrashk/kerl – follow instructions and add export PATH="$PATH:$HOME/.kerl"

to .bashrc (or .zshrc or any other .rc file)

Troubleshooting

If you get a debug message such as:

Kiex sourcing line not found in \( \sim \)/.bashrc, \( \sim \)/.bash_profile, \( \sim \)/.profile, \( \sim \)/.zshrc, or \( \sim \)/.zsh_profile

Add the following to your shell’s config file (.bashrc/.zshrc/.cshrc):

[[ -s "$HOME/.kiex/scripts/kiex" ]] && source "$HOME/.kiex/scripts/kiex"

Other useful commands

erl version will list the Erlang version, you will see something like: Erlang (SMP,ASYNC_THREADS,HIPE) (BEAM) emulator version 5.8.3

2.1.5 Option 2: Installing Elixir with asdf

The other option is to install Elixir with asdf.

In terms of version numbers for Elixr and Erlang, version numbers should be the ones you want to use. Here I do it with the latest ones available at the moment of writing.

Anyway, if you intend to work with several versions of erlang or elixir at the same time, or you are tied to a specific version, you will need to compile it yourself. Then asdf is your best friend.

Step 1 – On Linux, install needed system packages

On Linux, you may have to install the following packages if you don’t have them already.

Fedora

Ubuntu

Step 1a – On MacOSX, install needed system packages (via homebrew)

Step 2 – Install asdf and its plugins

asdf lives in https://github.com/asdf-vm/asdf

Follow its installation instructions, which at the moment of writing were:

For Ubuntu, other linux distros, or MacOSX

If you’re using Zsh shell, use these lines

Step 2a – On a new terminal, install Erlang and Elixir plugins:

Step 3 – Install Erlang and Elixir

Then set them as the global version:

Now you can open a new terminal and try erl:

Or start Erlang Observer by erl -s observer start.

And you can try ‘iex’:

Use asdf .tool-versions file to manage which version is active on each of your projects.

Enjoy!

2.2 Summary

As I said before, 50% of the battle in getting started with learning a new technology stack is getting setup with the right tooling. It’s more productive and more fun to get started the right way.

The tools are always changing in the programming landscape, so if you find a cool tool you like, I do hope you’ll share it with me so I can keep this guide updated for others as well as yourself!

3.1 Zen Masters and Adopting the Functional Mind

So let me tell you a story.1

Once, a long time ago, there was a wise Zen master. People from far and near would seek his counsel and ask for his wisdom. Many would come and ask him to teach them, enlighten them in the way of Zen. He seldom turned any away. One day an important man, a man used to command and obedience came to visit the master. “I have come today to ask you to teach me about Zen. Open my mind to enlightenment.” The tone of the important man’s voice was one used to getting his own way. The Zen master smiled and said that they should discuss the matter over a cup of tea. When the tea was served the master poured his visitor a cup. He poured and he poured and the tea rose to the rim and began to spill over the table and finally onto the robes of the wealthy man. Finally the visitor shouted, “Enough. You are spilling the tea all over. Can’t you see the cup is full?” The master stopped pouring and smiled at his guest. “You are like this tea cup, so full that nothing more can be added. Come back to me when the cup is empty. Come back to me with an empty mind.”

3.1.1 Learning Functional Programming Meant I Had to Let Go of the Object Oriented Mind

In Elixir, there is no such thing as “objects”. There’s no such thing as “classes”. Most importantly, you’ll hear a phrase “data is immutable”.

This means that values in a certain memory location don’t change. Often, you will see something like:

This is referred to as “binding” the value 2 to v. If you then did v = 3, this simply points v to a memory location that contains the value 3. The memory location that contains the value 2 still exists. That’s why you refer to this operation as “rebinding the variable v to the value 3” instead of “assigning 3 to v” the way you do in object oriented languages.

From a programming standpoint, now both 2 and 3 are in memory until they are garbage collected.

3.1.2 How This Immutable Thing Relates to Elixir Processes and “Let It Crash”

If you hang around the Elixir community long enough, you’ll hear the phrase “let it crash”, meaning to let a process (containing data) just crash if an unexpected error happens. A process never has access to another process’s data (and hence state), and so you don’t have to worry that losing one process will affect behavior or data in another process. It’s a recipe for a more stable system.

In object-oriented languages (like Java), where data can be mutated across threads, one thread can be updating while another can be reading from a data store, and so you need to worry about “protecting” state during concurrent operations.

The beauty and implication of the “rebinding” of the variable v, is that you have a guarantee that your data in a memory location won’t change. Said another way, the “data is immutable”.

3.1.3 Object-Oriented vs Functional

As I said before, one thing that you should be aware of right off the bat is that you’re going to have to let go of your old notions of programming via object orientation. You’ll see what I mean by that as we look at more of the Elixir language. For now, let’s look at the first syntactical difference – the lack of classes.

3.1.4 Modules vs Classes

If you’re coming from the Ruby world or some other object-oriented paradigm like Java, you may be used to dealing with the concept of classes. In Elixir, there’s no such thing as a class. Instead Elixir gives you a module, which is a way to group functions together.

The other interesting implication of not having classes is that there’s no such thing as “an instance of a class”, or in this case “an instance of a module”. You always call functions with the following syntax of ModuleName.function_name(arg1, arg2, …).

Below is an example of a Calculator module with an add function.

In a working Elixir program, you might have the Calculator perform some work with the following code:

3.1.5 Functions: Input X, Receive Y

Now that you’ve gotten a taste of Elixir modules and functions, I want to introduce one more analogy to help you wrap your head around the concept of functional programming. If you’ve ever taken an algebra class, you might be used to hearing about functions such as “f of x” (denoted f(x) for short).

You might have seen things like y = f(x) = x + 2 which means f(x) (or y) is the result of adding 2 to every input x. And that’s simply how Elixir operates – you take some data, transform it via a function, and voila, you have a new result, or a new piece of data to operate on.

If you haven’t taken algebra before, then you can think of it as a magician putting something into a hat (say a feather), and then pulling something else out of it, like a rabbit. One thing went in, and another came out.

3.1.6 Goodbye Inheritance

If you’re used to Ruby, you might be used to seeing inherited classes like the Dog class.

There’s no such thing as inheritance in Elixir. You just have modules that contain functions to operate on data.

3.1.7 Immutability

The other sticking point about Elixir that makes it different from an object-oriented language like Ruby is that data is immutable. In fact, hang around in the Elixir community long enough, and you’ll hear the word “immutability” thrown around a lot.

I already gave an explanation above, so I won’t rehash it. But to give it to you in the simplest terms, “data is immutable” means we never change data in memory, we only make copies of the data and transform it as necessary. The practical implication of this is that we don’t hold state in variables.

3.1.8 How do you do state?

This of course begs the question, then “how do you do state”? We’ll look at that in upcoming sections. For now, it’s sufficient to say that Elixir lets you hold state via a process mechanism. And it gives you tools like GenServer to help you do it.

3.2 Summary

It might take a little while for you to “empty your cup”, but hopefully the upcoming quizzes and projects will help you wrap your head around Elixir and functional programming concepts.

4.1 Everyone Loves the Count

When I was a little boy, I used to watch Sesame Street. The show had this character called Count von Count, or simply, The Count.

His job on the show was to teach kids about simple mathematical concepts like counting. Watching him made counting and other mathematical concepts entertaining and fun to apply.

4.1.1 But then I grew up and discovered the Enumerable module…

As a self-taught web programmer, my first language was Ruby, via learning Ruby on Rails. One thing that was new to me was the the Enumerable module and its methods. As I got used to it, I found the Enumerable module quite beautiful as it enabled me to easily and elegantly operate on array collections. JavaScript has similar methods and I’d be willing to be other object-oriented languages do as well.

In fact, if type “enumerable” into Google, I get the definition “able to be counted by one-to-one correspondence with the set of all positive integers.”

In fact, Ruby’s Enumerable module does feel like it’s designed to operate on a list of integers (or other “objects”). It became such a part of my toolset what I was hoping Elixir had one…

4.2 Introducing Enum…

Fortunately, Jose Valim, the creator of Elixir, was formerly a Ruby language programmer. So I’m betting he too appreciated the Enumerable module. And hence, we have the Enum module in Elixir.

Like the Enumerable module in Ruby, Elixir also provides us with the Enum module to work with collections. Typically, you’ll find yourself operating on lists and maps.

Lists look a lot like arrays in Ruby, but we’ll stick with the Elixir way of calling them lists.

4.3 Useful Enum Module Methods

Now let’s go over some useful Enum module methods. These are methods I find myself using over and over again in real world applications.

4.3.1 Enum#at

Let’s suppose we have the following list of integers bound to m.

What happens if we wanted to get the second element? In Ruby, you might do something like m[1]. You’ll find if you try that in Elixir you’ll get an error. Instead, you can use the at method of the Enum module as follows.

4.3.2 Enum#reduce

If you’re used to Ruby’s inject operator, you’ve probably seen things like:

The reduce method of the Enum module operates much the same way. Like all things in Elixir the major syntacitcal difference is that you call it using the module name follwed by the method name as follows:

Note that just like in Ruby’s inject method, the Enum#reduce method has an accumulator to hold the results of your computations.

4.3.3 Enum#map

Like Ruby, Elixir also gives you a map operator.

In Ruby:

In Elixir:

4.3.4 Enum#filter

Ruby gives you a handy select method to “filter” elements you want from an array. Below we select all elements from the array for which the condition holds true.

The Enum#filter method operates much the same way.

4.3.5 Enum#reject

Ruby’s converse of the select method is the reject method.

4.3.6 Enum#all?

Ruby also has an all? method which is extremely similar to Elixir’s. Or perhaps I should say it’s the other way around.

In any case, the all? method returns true if all the elements meet the condition.

Hopefully by now you’re seeing a common pattern. There are parts of Elixir’s syntax that borrow beautifully from Ruby (or should I say shamelessly copy?)

4.3.7 Enum#any?

Ruby also has an any? method to check if any element in a collection meets a particular condition.

Elixir also has an any? method.

4.3.8 Enum#to_list with a range

Sometimes you want to generate a long list of numbers but you don’t want to type it all out. The solution is to pass a range into Enum’s to_list method and let it do the work for you.

4.3.9 Enum#count

Sometimes you just want to know the length of a list. The count method can easily do that for you.

4.4 Summary

Like Sesame Street’s, The Count, the Enum module makes learning fun. The Enum module gives you quite a few useful methods for operating on data. I encourage you to read the documentation and discover even more methods. An upcoming quiz will ask you to make use of Enum’s methods, so stay tuned!

5.1 The Linked List Data Structure and the CSV Reporter

I did study Computer Science in university, and one thing they covered was the linked list data structure. In Ruby (and other object-oriented languages), you basically get these for free through arrays.

Instead of arrays, Elixir has a concept called “lists”. They look very much like arrays and behave much the same way. They are an Elixir version of linked lists.

5.2 Making a YouTube CSV Reporter

While building my first simple production application, I built an Elixir application that pulled down data from YouTube and turned it into a CSV (comma-separate value) report. It pulled down publicly available metrics and emailed them to a business unit that needed them for reporting purposes.

As I built this application, I found myself operating on lists of data in Elixir. In fact, I’d say all my real world application usage of Elixir involved Lists in some way. So it’s definitely worth familiarizing yourself with the List module in Elixir.

5.3 Useful List Module Methods

Like the Array module in Ruby, Elixir also provides us with a module to work with lists. Typically, you’ll find yourself operating on lists and maps.

Lists look a lot like arrays in Ruby, but we’ll stick with the Elixir way of calling them lists.

5.3.1 List.first

Here is the Ruby syntax for calling first on an array.

And here is the Elixir syntax for calling first on a list.

5.3.2 List.last

Here is the Ruby syntax for calling last on an array.

And here is the Elixir syntax for calling last on a list.

5.3.3 List.flatten

Ruby gives you a flatten method for arrays as follows.

And so does Elixir.

5.3.4 List.foldl

Off the top of my head, I don’t know of a Ruby equivalent for Elixir’s foldl method.

But the foldl method uses a function to reduce the list from the left. Below is a code snippet with an explanation of how the list is being folded.

5.3.5 List.insert_at

Elixir’s List#insert_at function is probably closest to Ruby’s Array#insert function.

Here is how you insert into an array at a particular index value. We insert the value 5 at index 1.

Here is the Elixir equivalent.

5.3.6 List.delete_at

When deleting an element out of a list in Elixir, you simply specify the index number at which you wish to delete the element.

5.3.7 ++ and – –

You can add elements to a list in Elixir with the ++ operator and remove them with the – – operator.

5.4 Summary

Lists are one of the most common data structures used in day to day Elixir development in my experience. It’s worth knowing the methods in that module as you will be using them frequently.

6.1 The Dictionary

If you’ve ever used Webster’s Dictionary, you know you look up a word, say “aardvark”, and flip through the pages to locate the definition. If you think of “aardvark” as a key of sorts, and then its corresponding definition as a “value”, you’ll have an analogy to the dictionary abstract data type.

Basically, you use a key to access a value. The first important property of a dictionary are that the keys are hashabale and equally comparable, which is often why keys are letters or numbers. The second important property is that the entries appear in no particular order (which is a contrast to Webster’s Dictionary).1

The Ruby language has an implementation of the dictionary data type called a Hash. So do other object-oriented languages like Java.

6.2 But what about Elixir?

Elixir has an implementation called a map. In fact, when I was building a reporting tool that emailed comma-separated value text files, I used the Map module quite a bit. As you work with Elixir, you’ll likely find that you use the Map module quite a bit as you transform and iterate over your data.

So let’s dive in to some useful map methods.

6.3 Useful Map Module Methods

Besides lists, the other data structure you’ll encounter frequently in Elixir are maps. I have found myself using them in everything I do,

6.3.1 Map.get

So Map’s get method lets you fetch a value by key. It’s very similar to the fetch method for a hash in Ruby.

You’ll notice from the above code, you have to be very specific about which key you use to fetch a value.

6.3.2 Map.put

Map’s put method is for putting a value associated with a key in a map. It can be used for adding new key and value pairs or updating old ones.

6.3.3 Elixir’s built-in syntax for updating maps

One cool trick I’ve learned from reading this blog post is how to do updating one or more map key values using a special syntax

6.3.4 Map.has_key?

Similar to a Ruby hash, Elixir gives you the ability to check if a given key is in a map.

6.3.5 Map.keys

Using Map’s keys function, you can get a list of keys only. This is analagous to Ruby’s keys function for Hash.

6.3.6 Map.values

Using Map’s values function, you can get a list of values only.

6.3.7 Map.replace

Map’s replace is handy in that it will alter the value associated with a key, but only if that key exists.

6.3.8 Map.merge

Map’s merge is another handy data transformation function I often find myself using to merge 2 maps together.

6.3.9 Map.drop

Map’s drop is good for removing keys from the list.

6.3.10 Map.to_list

Interestingly enough, I recently found out you could convert maps to a list of tuples.

6.3.11 Map.update

I haven’t used Map’s update too much, but it’s pretty handy for updating key values in a map. In the below example, code I used an initial value of “-1”, which is what the value of “a” would have been if it had not already existed in the map. Instead, the value of a is set to “1 times 3”, which is 3.

6.3.12 A word on nested maps

One thing I found that was hard to deal with was when I wanted to drop keys out of nested maps. To that end, I built a hex package called nested_filter to handle this. It’s a bit complicated at this point, but someone was kind enough to review it and if you go through the commit history you can see how it evolved.

We’ll probably come back to this later when we discuss anonymous functions, but I wanted it to mention it now in case you wanted to take a look.

6.4 Summary

The Map module is something you’ll use over and over again. It’s something I used in my first Elixir application for CSV reports and it’s something I still use in my production applications today.

7.1 Conditional Control Flow Structures

7.1.1 My Overreliance on Cond

When I first started with Elixir I tended to rely on conditionals much more than I would care to admit. This is because I wasn’t quite fluent with a concept called pattern matching, which is something we’ll talk about in upcoming course modules.

I tended to do things like:

Today I would cringe at that kind of code. A better improvement would have been to use a case statement (and an even better one would be the use of pattern matching). And that leads us to the topic of conditionals. We’re going to talk about cond, case, and if.

7.1.2 Cond

Coming from Ruby, cond reminds me of the if/elsif/end structure in Ruby. In other languages it’s equivalent to an if/else if type of control flow.

Its use case is to match on conditions. In the example below, you can see you hit the “catch all” true condition, which is like hitting the “else” portion of an if/else conditional flow in Ruby.

7.1.3 Case

In production ready code, I’ve seen the case conditional used quite a bit, especially when pattern matching against success and error tuples. Below is an example snippet in the context of a Phoenix controller. The hypothetical “DoSomething” module does something with the incoming params map and then the with_params method returns a success or error tuple.

From there, we let the phoenix controller decide what to render.

The underscore _ in the case statement acts as a catchall, much like the true in the cond statement.

7.1.4 If

The interesting thing to note about Elixir’s if statement is that unlike Ruby, there’s no concept of elsif. So you won’t run into a lot of nested if statements (hopefully) unlike in some of the Ruby startup code bases I’ve seen.

You can do nested if statements, but it’s ugly and I’ve never seen it any good codebase. So please do avoid it, although I will show it to you here for completeness sake.

7.1.5 Unless

Elixir’s unless statement follows the same pattern as its if statement.

7.2 Summary

As a general rule of thumb, a case statement is more idiomatic than cond, but cond has its uses. It’s rare to see if statements in Elixir, although it does happen.

8.1 The 2 Hardest Problems in Computer Science

There are only two hard things in Computer Science: cache invalidation and naming things. – Phil Karlton

So the quote from Phil Karlton I pulled from Martin Fowler’s website.1

And the longer I kept programming, the more I realized that Phil was right. Naming things – whether it be variables, classes, or files – is really hard. I can recall in my own object-oriented programming, how taxing it could be trying to name classes and methods in accordance with the problem domain I was looking at.

Unfortunately, functional programming with Elixir can’t solve this problem. However, there are tricks Elixir gives you to save you from typing your module names over and over.

When working with the Elixir frameworks such as Phoenix, you’ll find these tricks useful especially when dealing with the namespacing of modules.

In this section, we’re going to talk about handy keywords when working with Modules as well as Anonymous Functions in Elixir.

8.2 Alias and Import

Alias and import are two of the most common features of Elixir you’ll most likely be using when you first start using Elixir, especially if you’re using it in a web application (at least in my experience).

8.2.1 Alias

I think of the alias command as a shortcut to save you from typing. In actuality, you can do more with it.

For example, suppose you have the following module(s) defined.

We could have also aliased Project.Calculator.Adder as something else entirely with the as option as shown in the Project.Machine2 module.

The other thing you can do is alias more than one module in the same line. In the below example, I am aliasing the Project.Calculator.Arithmetic modules and the Project.Calculator.Subtracter modules in one line.

Try the source code for yourself by copying and pasting it in the iex shell.

8.2.2 Import

I think of import as a way to easily use functions from other modules without having to type out any part of the module name (unlike alias).

Here’s how that would look with our Calculator example.

Interestingly enough, I recently learned that import has an only option to let you only import macros or functions. You can also specify specific functions that get called as well. You’ll notice the numbers 2 and 3 in the code above. This tells Elixir to only import the function that takes 2 arguments or 3 arguments, respectively.

You can see this in the commented line in the previous code block example with Project.Machine.

8.3 Module Attributes

If you’re used to constants in Ruby, you might be wondering what is the best way to handle those in Elixir. So far, I’ve found 2 good ways, one is through using private functions (defp my_function, do: "private_constant") and module attributes.

Let’s go back to our calculator example and see how we can use them.

There’s a bit to unpack from the above sample code (which you can paste into your iex shell and try out).

@moduledoc and @doc are called reserved attributes in Elixir and provide module documentation and function or macro documentation, respectively. We haven’t talked about macros yet, but we will in an upcoming chapter. For now, you can think of macros as a part of Elixir’s metaprogramming facilities.

@version is a custom module attribute that we defined to hold the “version” information for a module. We could have defined it to be a list or even a tuple.

Typically, Elixir developers use it as a temporary storage facility in a module (e.g., like a constant).

8.4 Anonymous Functions

One cool feature I like about Elixir is its ability to handle anonymous functions as first class citizens.

An anonymous function can be defined as follows.

8.5 Summary

Naming things is still a hard problem whether you’re doing functional programming or object-oriented programming. Fortunately, Elixir does give you tools to at least save you some typing when you are constructing module namespaces and re-using module functionality.

9.1 The First Thing I Do When Getting Started With a Programming Language

Every program I’ve ever written comes down to dealing with data in some way. One of the first things I do when learning a new programming language is to get a sense of the data types available to me. For example, when I was doing Ruby on Rails work, and wanted to create database columns with numbers, I wanted to know how the Rails commands that auto-generated database table creation commands mapped to a database’s data types.

It’s also important to understand whether you’re dealing with a statically-typed language like Java, which means you have to declare upfront what type of variable it is (e.g., int a = 2;, which means a holds an integer), or a dynamically typed language like Ruby where variables can hold any kind of data.

Like Ruby, Elixir is a dynamically typed language. Unlike Erlang, Elixir will allow you to rebind a value to a variable. That’s why you can do:

So now it’s time to take a look at the data types available to you in Elixir.

9.2 Integers and Floats

Elixir has integers and floats as its primary way of representing numbers. And it has the Integer and Float modules with functions to allow you to work with those types.

9.2.1 Arithmetic

One nice feature Ruby gives you is the “%” or modulus operator for finding the remainder of a division operation.

Elixir gives you this through the “rem” function.

9.3 Boolean

Elixir gives you true and false as boolean values. Interesting enough, they are equivalent to their respective atoms.

9.4 Atoms

You’ve seen atom keys throughout this lesson in the various example map structures we’ve shown.

Elixir has a concept called atoms. An atom’s name is its value. If you’ve worked with the Ruby programming language, you’ll find they are analagous to Ruby symbols. If you’re coming from a language like Java or C++, I’m not sure there’s an equivalent analogy, so for clarity’s sake I’ll show a code example.

You can see in the above code example that :a and :b are both atom keys in a map.

9.5 Strings

Strings in Elixir are UTF-8 encoded and you use double quotes to represent them.

Note: single quotes denote character lists and mean something else entirely.

9.6 Lists

Lists are analogous to arrays in Ruby or other object-oriented languages like Java. We’ve seen them throughout the course in various examples.

9.7 Tuples

One interesting type that you don’t have an analogy for as a Ruby programmer is the tuple. You define a tuple with curly braces. Tuples can hold any kind of value and store data contiguously in memory.

What does this mean practically? It means you can use the Kernel#elem method to get a tuple element by its index is a fairly fast operation.

9.8 Summary

Ok, so now you’ve been given a crash course on the types available to you in Elixir. Coming up, we’ll be looking at comprehensions and some other concepts before we head into your first project.

10.1 The Misuse of Elixir’s Comprehensions

So having some minor experience with Java and other object-oriented languages, I was curious if Elixir had a “for loop”, “while loop” or some other kind of looping construct.

And when I found the “for” keyword in Elixir, I thought “finally”. And of course I tried to use it like a “for loop” in an object-oriented language where I stored a piece of stateful information in a variable and expected it to be available later….Oops. I think I was trying to implement a version of the Traveling Salesman Algorithm.

10.1.1 The Purpose of Comprehensions

If you recall the Enum module in Elixir, there were sets of operations that allowed you to loop over a list/collection, and transform the list into another one.

Comprehensions are simply another way of doing this. The Elixir documentation refers to comprehensions as “syntactic sugar” for such operations.

10.1.2 A Simple Example of a Comprehension

To get an idea of what comprehensions can do, let’s look at a simple example.

As a comparison, you could have done the above example with a map such as in the below example.

10.1.3 Multiple Generators

In the above example comprehension x <- [3, 4, 5] is referred to as a generator. You can have multiple generators in a comprehension.

You can see what happened. First, 3+1 and 3+2 were computed. Then 4+1 and 4+2 were computed. Finally, 5+1 and 5+2 were computed.

10.1.4 Extracting Data Using Pattern Matching

You can also use comprehensions in to transform a keyword list (list of tuples) into a different data structure, such as a list. If you look closely at the code below, you’ll notice you’re pattern matching.

10.1.5 Filtering in Comprehensions

If you recall from the article/video on Enum, there was a filter function that allowed you to select elements that met a certain condition. Comprehensions allow you to do this too. Look at the example below.

And with the above pattern matching and filtering mechanism provided to us by comprehensions, we select only the keys associated with odd values.

10.1.6 Into a Map

Let’s be honest. Sometimes you don’t want lists, you want a map. And you can have that with the handy :into option.

In actuality, you can apply :into to any structure in Elixir that implements what’s known as the Collectable protocol. We are going to touch on protocols in an upcoming section, so I will hold off on defining them for now. Suffice it to say, you can pass in a list, map, or string into the :into option.

10.2 Summary

So hopefully you’ve gotten a good overview of what you can do with comprehensions. And the next time you see the for keyword in an Elixir program, think “comprehension” not “for loop”.

11.1 When IO.inspect Let Me Down With a Character List

So in other languages, sometimes you want to output the contents of an array to see what it contains. For example, in the Ruby programming language, if I have an array a = [8, 9, 10, 11], I can do the following.

Notice how I can see the array contains 8, 9, 10, and 11.

When I started with Elixir, I found I could more or less do the same thing with IO.inspect. But one day, I was let down with a surprise. I did the following.

WTF is going on?

11.1.1 But first, we need to talk about binaries

To answer that, we have to learn about binaries. A binary is simply a sequence of bytes in Elixir. And a byte is simply 8 bits. And in computer-ese, a bit is simply a 0 or 1.

11.1.2 Let’s see how to represent a binary with actual code

Below is a code block that shows you how to represent a binary.

Now, the double angled brackets (« ») defines a new bitstring. Each bitstring is composed of many segments, each of which has a type. There are 9 types of segments that can be used in bitstrings including integer, float, utf8, utf16, and utf32.

11.1.3 What does this have to do with strings again?

Strings are a subset of binaries. Specifically, strings are a valid UTF-8 sequence of bytes. How do you know if you have a valid string on your hands? Fortunately, Elixir’s String module gives you a way with the valid? method.

11.1.4 Single versus double quotes

The other thing you’ll notice when dealing with strings in Elixir is the double-quoted and single-quoted strings.

11.1.5 Properties of double-quoted strings.

Before we dive into what single-quoted strings are, let’s talk about what you can do with double-quoted strings in Elixir. Here are the two most common use cases.

Common Use Case 1: Variable Interpolation

In some of the production-grade Phoenix web applications I’ve been writing, I’ve found variable interpolations in strings quite handy. For example, if I want to embed a dynamic link URL that changes depending on what “category” it is, I might do something as shown in the below code block.

If you’re familiar with a dynamic object-oriented language like Ruby, then this style of interpolation might look quite familiar to you.

You can also think of variable interpolation as an alternative way to concatenate strings.

For example, this is the “regular” way to concatenate strings:

But you could also do it this way:

Common Use Case 2: Documentation

In Elixir modules, you’ll often see strings used to document modules. Below is an example from a hex package I wrote called nested_filter.

11.1.6 Single-quoted strings are character lists

Remember from the paragraphs above how inspecting a list of integers produced the following?

Each of those characters is a codepoint, or a character. Each codepoint is represented by what’s known as a code unit, which refers to the number of bits an encoding uses. Examples of encodings include UTF-8 (8 bit encoding) and UTF-16 (16 bit encoding).

So when Elixir prints out a character list like the above example, it really prints out the UTF-8 codepoints that the character list of integers represents.

How do you avoid printing out the character representations?

Before I tell you, let me show you a really cool trick. Boot up an “iex” prompt and type h Inspect.Opts.

You should see something like:

Notice the “:as_lists” argument you can pass to the “:charlists” option. The following code example illustrates this:

When you pass in the “:as_lists” argument, you get back a list of integers from calling IO.inspect.

Note: the :as_lists option is for Elixir >= 1.5. According to this stackoverflow post1, with Elixir < 1.4, pass “false” as an argument to the “:char_lists” option.

You previously saw this before in the discussion of double-quoted strings, but I’ll include the example below again for convenience.

11.1.7 Heredocs

Finally, no discussion of strings would be complete without at least mentioning Heredocs. Heredocs are multiline strings which are used to document code in Elixir (at least, that’s the way I’ve mostly seen them).

12.1 Looking at Timex

When I first started learning about Elixir, one of the first open source libraries I came across was Timex. Within that library, I came across the [Types module[(https://github.com/bitwalker/timex/blob/master/lib/timex/types.ex){:target=”_blank”}.

Within that library, I saw the following code…

And I wondered what is this “@type” syntax?

12.2 The Philosophy of Documentation as a First Class Citizen

Before we get to the actual way to write documentation in Elixir, let’s briefly dive into a phrase you’ll often hear – “documentation as a first class citizen.” What does this mean? From Elixir’s documentation itself, it means “documentation should be easy to write and easy to read.”

12.3 The Syntax for Writing Documentation – Markdown

The way to write documentation in Elixir is by using markdown syntax. There are plenty of tutorials such as this one by GitHub that cover this syntax, but I’ll give you a quick overview to get started.

Markdown is simply a shorthand syntax that eventually gets parsed into HTML.

12.3.1 Headings

The pound sign (#) is used to create HTML heading tags. One pound sign is equivalent to an “h1” tag and six pounds signs is a “h6” tag.

12.3.2 Code blocks

You can use backticks (‘) to specify blocks of code that will be prefaced with “pre” or “code” tags when converted to HTML.


defmodule DemoCode do
def hello, do: "hello"
end

12.3.3 Lists

Since markdown gets converted to HTML, you can have ordered and unordered lists.

Ordered Lists

For ordered lists, you use numbers followed by periods. For example:

  1. item 1
  2. item 2
  3. item 3

Unordered Lists

For unordered lists, you use pluses, asterisks, or hypens. For example:

  • item 1
  • item 2
  • item 3

12.3.4 Basic Styling of Text

If you need to italicize text, use asterisks or single underscores. For example:

*This text will be put into an tag*.

You’ll end up with html that looks like:

12.3.5 External Hyperlinks

If you need to annotate a hyperlink in markdown, you use square brackets that enclose descriptive text surrounded by parentheses that contain the hyperlink.

It looks like the following:

This link goes to my blog post on nested filter.

Ok, so now you have a brief overview of markdown. It’s time to start documenting!

12.4 Documenting Your Elixir Code

Erlang has the notion of something called module attributes that applies in Elixir. In Elixir code, module attributes are often used to define constants or as a temporary storage holder for values to be used during code compilation.

When documenting Elixir code, you’ll rely a lot on the reserved attributes “@moduledoc” and “@doc”.

12.4.1 Documenting Modules

When documenting modules, you’ll use the @moduledoc attribute. The following is an example.

What if you didn’t wish to document this module?

Then you could set @moduledoc to false. So it would look like this:

Documenting Modules With Style

Believe it or not, there is a proper style to document modules via this community style guide. Right now Elixir is pretty new, so this could change, but I think it serves as good guidance for now.

The basic tenets are:

  • The @moduledoc attribute should be included right after the “defmodule” line.
  • Separate the @moduledoc documentation with a blank line between the end of the documentation and new code.
  • Be sure to use heredocs for the description text for @moduledoc.

12.4.2 Documenting Functions

When documenting functions, you’ll use the @doc attribute. We now document the function in the HelloWorld module in the following example.

What if you didn’t want to document this function? Similar to module documentation, you can set @doc to false.

12.4.3 A Word on Documenting Private Functions

So the big deal here is that you can’t. You’ll get a stern warning from Elixir and your documentation description will be ignored.

12.4.4 Typespecs

Remember how I mentioned the Timex library?

Even though Elixir is a dynamically typed language, it still gives you functionality for documenting typed function signatures and declaring custom types.

Declaring custom types is what the Types module in the Timex library did.

@type attribute

To understand the @type attribute for declaring custom data types, let’s look at a portion of the Timex.Types module again.

Notice the types megaseconds, seconds, and microseconds. They are defined as a “non_neg_integer”. Now a “non_neg_integer” is a built-in type specification. You’ll find that Elixir steals a lot of its built-in type specifications from Erlang and expresses it the same way.

Now notice the timestamp type. This is the custom day type that is defined. It is a tuple composed of the built-in types.

Basic Types in Elixir Documentation

I’m printing out the basic types in Elixir here as a convenience. I pulled it from the Hex docs.

@spec and @typedoc attributes

Now let’s look at how to use @spec and @typedoc.

Note that @typedoc is used to describe the @type you’re defining.

The @spec is being used to specify the function specification.

From a proper coding convention perspective, note that we group @typedoc and @type together and separate it from additional code with a blank line and we keep @spec directly above the function definition with no blank line.

@opaque and @typep

So two module attributes worth mentioning that I didn’t know about when I first started learning Elixir are @opaque and @typep.

Now any type defined via @typep is considered private.

@opaque is used to define a public facing type while keeping the structure of the type out of the public documentation.

12.6 Documentation NestedFilter and Digger

In learning about Elixir I wrote two hex packages. One was nested_filter and the other was digger. They both contain examples on how to document your Elixir code. If you notice an issue, pull requests are welcome!

12.6.1 Summary

Hopefully you now have a feel for how to document your Elixir code. Even though Elixir is a dynamically typed language, it still gives you the ability to specify your data types via documentation. I really like this because I feel like it can help make the intent of your code more clear.

13.1 Where does to_atom come from?

As I dove deeper into Elixir, I started using guard clauses. So I would end up writing functions with guard clauses that looked like the following:

One day I started wondering where functions like is_atom were coming from and why I never had to call out a module name to have access to them, the way I would have to do with Enum.map/1 as an example.

For the next few sections, we’re going to talk about some interesting Kernel functions and cover guard clauses.

13.2 Diving Into Kernel’s Interesting Functions

The Kernel module has some useful functions that are handy to know as you’re going about your day to day Elixir programming.

13.2.1 The is_* functions

The first set of functions that are handy are what I affectionately term the “is_*” (pronounced “is star”) functions.

Here’s a list and their description straight from the Elixir documentation:

  1. is_atom – Returns true if term is an atom; otherwise returns false.
  2. is_binary – Returns true if term is a binary; otherwise returns false.
  3. is_bitstring – Returns true if term is a bitstring (including a binary); otherwise returns false.
  4. is_boolean – Returns true if term is a floating-point number; otherwise returns false.
  5. is_float – Returns true if term is a floating-point number; otherwise returns false.
  6. is_function – Returns true if term is a function; otherwise returns false.
  7. is_integer – Returns true if term is an integer; otherwise returns false.
  8. is_list – Returns true if term is a list with zero or more elements; otherwise returns false.
  9. is_number – Returns true if term is either an integer or a floating-point number; otherwise returns false.
  10. is_pid – Returns true if term is a PID (process identifier); otherwise returns false.
  11. is_port – Returns true if term is a port identifier; otherwise returns false.
  12. is_tuple – Returns true if term is a tuple; otherwise returns false.
  13. is_map – Returns true if term is a map; otherwise returns false.
  14. is_nil – Returns true if term is nil, false otherwise.

13.2.2 Binaries and Bitstrings: A Simple Explanation

One point that deserves a bit of further elaboration is the difference between binaries and bitstrings.

Let’s look at an example in code.

There’s a wonderful explanation from this forum post that describes this perfectly that I will quote here:

In Elixir, a “bitstring” is anything between <> markers, and it contains a contiguous series of bits in memory. If there happen to be 8 of those bits, or 16, or any other number divisible by 8, we call that bitstring a “binary” – a series of bytes. And if those bytes are valid UTF-8, we call that binary a “string”.

What does that mean for our example?

Think of strings as a subset of all binaries, and binaries as a subset of all bitstrings. So from the example, you can see that “hello” is 40 bytes long which is divisible by 8. So it is a binary and since it is also valid UTF-8, it is also a string.

13.2.3 The data structure functions

There’s some other interesting functions that have to do with maps and lists, so I call them the “data structure functions”. Here they are with a description for your convenience.

  1. bit_size – Returns an integer which is the size in bits of bitstring.
  2. byte_size – Returns the number of bytes needed to contain bitstring.
  3. elem – Gets the element at the zero-based index in tuple.
  4. get_in/2 – Gets a value from a nested structure.
  5. hd – Returns the head of a list.
  6. length – Returns the length of list.
  7. pop_in – Pops a key from the given nested structure.
  8. put_elem/3 – Inserts value at the given zero-based index in tuple.
  9. put_in/3 – Puts a value in a nested structure.
  10. tuple_size/1 – Returns the size of a tuple.
  11. update_in/3 – Updates a key in a nested structure.
  12. map_size/1 – Returns the size of a map.
  13. tl – Returns the tail of a list.

13.2.4 The math functions

There’s some other interesting functions that have to do with arithmetic, so I call them the “math functions”. Here they are with a description for your convenience.

  1. div/2 – Performs an integer division.
  2. round/1 – Rounds a number to the nearest integer.
  3. max/2 – Returns the biggest of the two given terms according to Erlang’s term ordering.
  4. min/2 – Returns the smallest of the two given terms according to Erlang’s term ordering.
  5. +/2 – Arithmetic addition.
  6. */2 – Arithmetic multiplication.
  7. //2 – Arithmetic division.
  8. abs/1 – Returns an integer or float which is the arithmetical absolute value of number.

13.2.5 Miscellaneous functions

Finally, there are some other interesting miscellaneous functions. Here they are with a description for your convenience.

  1. apply/3 – Invokes the given fun from module with the list of arguments.
  2. function_exported?/3 – Returns true if module is loaded and contains a public function with the given arity, otherwise false.
  3. macro_exported?/3 – Returns true if module is loaded and contains a public macro with the given arity, otherwise false.
  4. self/0 – Returns the PID (process identifier) of the calling process.
  5. make_ref/0 – Returns an almost unique reference.

13.3 Summary

I hope you enjoyed this whirlwind tour of the Kernel module. There’s more functions I didn’t cover, but I wnated to give you a highlight of some of the ones you would likely use in your coding endeavors.

14.1 Pattern Matching: When You Have a Hammer Everything Looks Like a Nail

So I was coding a new Elixir hex package in the fall of 2017 called Digger. The whole point of this package was to make it easy to ensure any key in a map was a string (“stringify-ing” map keys) or an atom (“atomizing” keys).

At that time, I was familiar enough with Elixir to avoid abusing the “cond” and “case” statements and to use pattern matching.

In atomizing keys, I wound up with a module like the below. Note there is only one public function called “atomize”. The rest of the functions are private and support the “atomize” function.

The module to convert map keys to strings had an analogous interface.

If you look at the above code, you’ll notice I started using guards to decide how to atomize a key based on the type of data it was. For example, if it was an integer, the “atomize_key” function used the to_string function to convert the key to a string and then called the. For a struct, I actually wouldn’t try and “atomize” it and kept using the struct as the key.

If only there were a mechanism in Elixir so that would let me dynamically call a function depending on a value’s type. This would let me more easily extend this module’s API for newly defined data types.

14.2 Enter Protocols: What Are They?

Before we talk about protocols, we actually have to take a quick detour to talk about polymorphism.

14.2.1 Ok, so what is polymorphism?

From Wikipedia: “In programming languages and type theory, polymorphism (from Greek πολύς, polys, “many, much” and μορφή, morphē, “form, shape”) is the provision of a single interface to entities of different types.”1

More from Wikipedia:

  • Ad hoc polymorphism: when a function denotes different and potentially heterogeneous implementations depending on a limited range of individually specified types and combinations. Ad hoc polymorphism is supported in many languages using function overloading.
  • Parametric polymorphism: when code is written without mention of any specific type and thus can be used transparently with any number of new types. In the object-oriented programming community, this is often known as generics or generic programming. In the functional programming community, this is often shortened to polymorphism.
  • Subtyping (also called subtype polymorphism or inclusion polymorphism): when a name denotes instances of many different classes related by some common superclass.

Apparently, according to Wikipedia, Elixir uses parametric polymorphism and the functional programming community just refers to it as “polymorphism.”

Also interestingly enough, while Elixir is a dynamic language, Wikipedia states “parametric polymorphism is a way to make a language more expressive, while still maintaining full static type-safety.”2

14.2.2 Protocols Defined

So after all that, what are protocols?

The Elixir documentation states “Protocols are a mechanism to achieve polymorphism in Elixir.”3

In layman’s terms that means we depend on function arity and the data types passed in to the function to determine which protocol implementation to dispatch.

14.2.3 Practically speaking, how do you use protocols in Elixir?

You only need to remember 2 syntax keywords when using when working with polymorphism in Elixir: defprotocol and defimpl. As we step through the following case study with the hex package Digger, hopefully it will become more clear.

14.2.4 A Case Study On Using Polymorphism: Rewriting the Digger.Atomizer Module Using Protocols

So now let’s step through a small case study by rewriting the Digger.Atomizer module.

14.2.5 Step 1: Define Your Protocol with defprotocol

14.2.6 Step 2: Define Your Implementation with defimpl

For string keys, here is the implementation of the protocol.

14.2.7 Step 3: Implement Any as a Fallback

In the following code example, you’ll notice we define a protocol implementation for “Any”. This is to let Elixir know what to do in case it can’t find a function implementation for a particular data type.

In the definition of the protocol itself, we also set the @fallback_to_any attribute to true.

Alternatively, you can use the @derive attribute in a module to tell Elixir to use the “Any” implementation for that module.

What if the implementation of Digger.Atomizer.Protocol had not been applicable to any data type?

From the Elixir documentation:

“That’s one of the reasons why @fallback_to_any is an opt-in behaviour. For the majority of protocols, raising an error when a protocol is not implemented is the proper behaviour.” “Which technique is best between deriving and falling back to any depends on the use case but, given Elixir developers prefer explicit over implicit, you may see many libraries pushing towards the @derive approach.”

14.4 Other Tips

  • According to this blog post, a protocol implementation can use the @for module attribute as an alias of the current target. It’s handy for different protocol implementations.

14.5 Summary

Consider using protocols when you find yourself writing functions whose implementation soley depends on the data type(s) being passed in.

Chapter 15 Behaviors and Protocols

One thing I’ve always loved is efficiency. I love checklists and templates so I don’t have to think about repeatable processes. Templates can help keep you really organized. When I did some freelancing, I had a contract template that I could edit to quickly make changes. It saved a ton of time.

15.1 And what does this have to do with behaviors?

In an analogous fashion to the contracting templates I used to use, Elixir defines behaviors for modules. Behaviors let you define a module and specify what functions must be a part of the module.

15.2 Defining Behaviors

The way to define a behavior is through a “@behaviour” attribute. The module whose “behavior” you are implementing must use the @callback attribute to define the functions that are part of the contract it will enforce to all modules that wish to use its “behavior”.

15.2.1 In coded English, a behavior does the following

15.2.2 Use the @callback attribute to specify the functions that are part of the @behavior contract

The @callback attribute in the example above tells Elixir that the “hello” function that takes a bitstring argument must be part of any module that wishes to implement the Hello module behavior.

What happens if you fail to implement the method specified by callback?

I experimented in the iex shell and found I got a warning:

So no one will revoke your license to program, but it looks like not including the contractualy specified behavior is frowned upon.

15.3 Dynamic Dispatching

One interesting thing you can do with behaviors is dynamically dispatching to a specific implementation. Let me give you a quick and contrived example.

Below is some sample output from an iex shell:

Notice how easy it is to dynamically dispatch based on a module.

15.4 Relation to Protocols

The following table I pulled from a blog post by a man named Samuel D.1 It gives a nice comparison between protocols and behaviors.

ProtocolsBehaviors
Apply to data structuresApply to modules
Specify new implementations of existing functions for new datatypesSpecify a public spec/contract for modules to implement
“Here’s my datatype, it can X”“Here’s my module, it implements Y”
Exclusive to ElixirProvided by the Erlang runtime

The main idea is that protocols can be thought of as “template” functions for handling different data types while behaviors can be thought of as “template” contracts that tell modules what functions to implement.

15.5 Summary

Elixir behaviors can be a great tool for helping to organize your code by specifying contracts and keeping your coding intentions clear.

Chapter 16 Guards

Sometimes I’ve found myself wanting to only call a certain function depending on a certain condition. For example, I might only want to call a function when one of the parameters is greater than the other.

I did this in a production Phoenix application recently when I was trying to recursively generate a routing path

16.1 What is a guard?

Elixir guards are special little clauses denoted with the keyword when that are used to apply extra checks on pattern matched functions.

Here’s a quick concrete code snippet:

So in the above snippet, this function will only be called when the condition “k > j” is met and they are both integers.

16.2 Why Use a Guard?

Like I said before, I found myself reaching for guard clauses when I want to apply a check on the parameters I pass into a function.

16.3 Types of Functions You Can Use With Guards

So remember in Chapter 13 A Tour of Kernels, we described the is_ functions like is_integer, is_atom, and so on? Also, do you recall the data structure functions such as byte_size, map_size, and so on?

Well those are the functions that are allowed in guards. The complete list is documented in the documentation.

16.4 Why You Can’t Use Custom Functions with Guards

You can also use the typical logical operators like &&,, and !.

For convenience, I’ll quote from the documenation below.

16.4.1 Operators and Functions You Can Use in Guards

Operators

comparison operators (==, !=, ===, !==, >, >=, <, <=) strictly boolean operators (and, or, not) (the &&, ||, and ! sibling operators are not allowed as they’re not strictly boolean – meaning they don’t require both sides to be booleans)
arithmetic binary operators (+, -, *, /)
arithmetic unary operators (+, -)
binary concatenation operator (<>)
in and not in operators (as long as the right-hand side is a list or a range)

Functions

Below are the built-in Elixir functions you can use with guards.

The documentation is a quick read that shows you all the details, and I encourage you to give it a read if you’re able.

16.4.2 Why You Can’t Use Custom Functions With Guards

Once I tried using my custom function as a guard clause. It didn’t work.

Why?

With the way Erlang executes functions, each function is tested from top to bottom of the code. If a guard clause were allowed to have a side effect, then you couldn’t guarantee functional purity.

To ensure that guard clause functions have no side effects (i.e., “pure functions”) and executed quickly, this blog post by Chris Keathley1 stated that Erlang’s authors decided to limit guard clause functions to Erlang’s built-in functions.

16.4.3 Or Can You Use Custom Functions?

Sort of. You can define your own guards using Elixir macros. However, you still must use Elixir’s built-in functions and operators for the guards to be valid.

Example Macro Guard

16.4.4 Introducing defguard(p) in Elixir 1.6

As of Elixir 1.62, you now have defguard/1 (or defguardp/1) to define guard macros. This helps you avoid unnecessarily complicated metaprogramming voodoo depending on whether or not the function is being invoked in a guard or not as described in this github issue.

16.5 Summary

Overall, I’ve found guard clauses to be useful, especially when I need to quickly apply a conditional check on function parameters.

Chapter 17 IO and Files

Not too long ago I was working on modifying an endpoint in a Phoenix web application that allowed you to upload a CSV file and insert that data into a database table.

In that code I noticed a reference to File.stream!. And so I began digging further.

17.1 File Module and Functions

There’s a bit of interplay between the File and IO modules in Elixir. Since files are opened in binary mode by default, developers have to use IO.binwrite/2 and IO.binread/2 functions when reading and writing files.

If you want to tell Elixir to to interpret a file as utf8, you can open it with the :utf8 encoding option.

17.1.1 Bang and Non-Bang Function API

The bang file methods (denoted with a ! after the method name) typically raise an error on failure and return :ok on success.

The non-bang functions typically return an error tuple on failure and return :ok on success.

17.1.2 File Function Examples

So let’s take a look at some basic file functions. You’ll notice quite a few of the functions in the File module are named after their Unix/Linux cousins.

cd/1

Below I set the current working directory.

stat/2

Next, I get some stats on a file I created in /Users/bruce.

atime indicates the last time the file was read. For Unix systems, ctime is the last time the file or inode was changed. In Windows, it is the time of creation. The links field indicates the number of links to the file. The size field gives the size of the file in bytes.

chmod/2

Similar to the analagous Unix command, you can change file permissions. The only difference is you use octal flags.

Below is an example.

Here are the flags reprinted from the documentation for your convenience.

dir?

This handy method lets you inquire if a file is a directory.

exists?

You can figure out if the path (or file) exists.

read/1

On success, the read/1 function returns a tuple with a status and binary data object that contains the contents of the file.

rename/2

You can also rename files. :ok is returned on success, otherwise {:error, reason} where reason is the reason for the error.

regular?

This function checks if a file is “regular”. In layman’s terms this means it checks to see if it’s an executable, a file containing ASCII text, zip file, etc.

You can check on your command line for regularity of a file with:

As you can see, my .vimrc file is a regular file.

In an Elixir iex shell, you can do:

Note that directories in Unix and Linux are “binary files” that locate other files and directories.

write/3

And of course, no File module would be complete without a write function. Below I wrote the word “hello” out to a file called “toss2.txt”.

There are different modes which are documented here in the File.open/2 method.

17.2 Path Module

If you look at the File documentation, you’ll notice it typically takes paths as arguments. So I am jotting down some notes about some useful Path functions I found from reading the documentation.

17.2.1 Path Function Examples

absname/1

This handy function converts the path passed in to an absolute path name. For example:

basename/1

The basename function returns the last component of the path, whether it’s a file name or folder, or the path if there are no directory separators.

dirname/1

If a path contains a file name, dirname/1 returns the directory component.

join/1

This function takes a list of paths and joins them together, removing any trailing slash on the join.

wildcard/2

One interesting function I found was the wildcard/2 function. It traverses paths according to the “glob” expression passed and the wildchard characters passed as options.

Here are the special characters from the documentation

? – matches one character
* – matches any number of characters up to the end of the filename, the next dot, or the next slash
** – two adjacent *’s used as a single pattern will match all files and zero or more directories and subdirectories
[char1,char2,…] – matches any of the characters listed; two characters separated by a hyphen will match a range of characters. Do not add spaces before and after the comma as it would then match paths containing the space character itself. {item1,item2,…} – matches one of the alternatives Do not add spaces before and after the comma as it would then match paths containing the space character itself.

17.3 IO Module and Functions

I’ve found myself using the IO module when doing basic debugging when I first started learning Elixir. Namely, I was using IO.puts/2 and IO.inspect/2.

17.3.1 IO Function Examples

But there are also some other handy IO functions.

binread/2

binread/2 lets you read from a “device”. If you look at the documentation, this ends up being an atom or pid (process id).

In the example, I read from standard input and pass in the :line option. This lets binread/2 know how to iterate through the device (e.g., line by line or a certain number of bytes).

gets/2

gets/2 lets you read one line from an IO device. :stdio is the default device.

In the below example, I specify :stdio to show you the argument parameter, though I didn’t actually need to.

puts/2

When I started with Elixir, the first thing I used to debug code was IO.puts/2.

puts/2 writes an item to a device (the default is :stdio) and adds a newline at the end.

As you can see from the error above, puts/2 will not work with maps (or tuples).

inspect/2

Fortunately, Elixir also has inspect/2 which can be useful for debugging. inspect/2 doesn’t change the argument passed in but returns it unchanged. So you can use it in your code to get a peak at raw values, including maps and tuples (and other pieces of data where IO.puts/2 will throw an error).

A Word on Inspect.Opts for Debugging

You’ll notice in the following example Elixir treats the list of integers as ASCII codes and outputs their letter representation.

To avoid, this you can turn to the Inspect.Opts module which defines the options used by inspect. To print out numbers, you can pass the :as_lists option as seen below.

You can review the other options, but one of the most useful ones I’ve found is the ability to print out a non-truncated list. In the example below you can see I use the :infinity option to see the whole list of numbers from 1 to 100.

Together with :as_lists, this should make your early debugging life much easier.

iex(3)> IO.write(:stdio, “hello world”)
hello world
:ok

iex(1)> {:ok, file_descriptor} = File.open(“hello world”, [:ram])
{:ok, {:file_descriptor, :ram_file, #Port<0.1181>}}
iex(17)> :file.read(file_descriptor, 12)

Chapter 18 Building a Random Image CLI Loader

The best way I have found to learn new concepts is to try and build something with what you just learned. That’s why I do all the katas. So to help ingest our learnings for files, let’s write a CLI (command line interface) application that helps us pick a set of files to randomly open.

18.1 Case Study: Building a Random Image CLI Loader with EScript

I’ve previously written a tutorial on building an escript CLI application, but we’re going to build another one that does a bit more in this post.

18.1.1 Step 1: Initialize a mix application

The first thing to do is to initialize our mix application. I’m passing in the *–sup arguments. This is to initialize the application with some supervisor and umbrella application defaults. It’s more for my own amusement than having anything to do with the application.

Below is the mix command I issued and its associated output.

I also did a git init . command in the image_loader repository so I could use Git version control.

18.2 Step 2: Add yaml-elixir and Write Tests

Next, I add a yaml parser via yaml-elixir in my mix.exs file.

Test Structure

Below are the tests I wrote. Notice I only test the path generation functionality. I could actually check the status of the images when they’re opened, but I chose not to do that.

18.2.1 Step 3: Setup Yaml Structure / File

18.2.2 Step 4: Open Images

Below is the code used to randomly open up images. The main functions are image_paths, which produce the file paths to the images so the System.cmd can know which files to open, and open_images, which does the actual work of opening the images.

The function read_yaml_from_file_path parses the yaml file into a map to be parsed through by Elixir.

18.2.3 Step 5: Convert to Escript

I’ve written about building a CLI with Escript before, but I’ll reiterate the steps here for convenience.

Step 5a: Configure escript in mix.exs

The first thing to do is to specify the module with a “main” function that serves as the main module in mix.exs.

Step 5b: Add a module with a main function

Next, add the module with the main function that you specified in mix.exs.

Step 5c: Build the escript

Finally, build the escript.

18.2.4 Step 6: Run the CLI program

Now, you can run the CLI program. Below I run the script using the path to the test.yml file that is included in this program.

18.3 Summary

Hopefully this CLI tool has given you a feel for what you can do with some of Elixir’s file related modules. Coming up soon, we’ll talk about errors in Elixir.

Chapter 19 Everyone Makes Mistakes: Errors in Elixir

I once took a class in watercolor painting. The instructor would have us sketch a bit, and then we’d start adding our paint. You had to be very careful not only with the amount of water you used, but also to let certain areas dry before you attempted to paint. Otherwise the colors would run together and there was no going back. There was no such thing as being able to “rescue” errors in watercolor painting.

Fortunately, Elixir does provide error handling.

19.1 Elixir Philosophy: Let It Crash

If you hang around the Elixir community long enough, you’ll hear phrases like “let it crash.” This refers to the fact that Elixir can do things like let an exit message from a dying process be used by a supervisor to decide what to do.

19.2 Conventions

In Elixir, the convention is to create a non-bang function such as hello_world/1 that returns a tuple consisting of a status and a result (e.g., {:ok, result} or {:error, reason}).

You also create a bang function that returns the result or raises an exception. For example., hello_world!/1 could return “result” or raise a HelloException.

19.3 Error Handling Keywords

Before diving in to error handling, let’s go over some of the basic keywords you’ll encounter.

19.3.1 try

The try keyword tells Elixir to enter into the block and “try” something that may result in an error.

19.3.2 catch

The catch keyword can be used with try, although as the Elixir documentation points out, it is very uncommon to use it this way. Instead, you’ll use it with the throw keyword.

19.3.3 throw

Throw is used in conjunction with catch in situations where it is not possible to get a value without using throw/catch.

19.3.4 rescue

Rescue allows you to specify what happens when a certain exception is raised.

19.3.5 raise

Raise is the keyword that allows you to raise an error in Elixir.

19.3.6 after

The after keyword specifies something that must always happen.

19.4 Examples of Try/Rescue

Let’s look at using try and rescue in practice.

19.4.1 Example From the Phoenix Framework

Let’s say we had a method to fetch a “Car” model in Phoenix. With a bang get!/1 method, an Ecto.NoResultsError is raised.

You could also omit the “try” block and simply use rescue.

This example fits the canonical use case of using raise/rescue for exception handling. This is for unexpected situations your program gets into.

19.5 Examples of Throw/Catch

When you have expected failures, it’s time for throw/catch. I’ll summarize the findings from this StackOverflow answer1 on throws which gives some more interesting insights and you can read if you’d like.

The Elixir documentation2 says that throw/catch is good to use when interfacing with library code that does not provide a “proper API”.

As an example, let’s say Elixir didn’t provide a way to delete an element(s) from a list.

Then you might use throw this way: