Getting Started with Elixir - Control Flow

Control flow expressions are not used as often in Elixir as with more imperative languages mainly because controlling execution flow can be handled with a mix of pattern-matching, multi-clause functions and guard clauses.

Control flow expressions are not used as often in Elixir as with more imperative languages mainly because controlling execution flow can be handled with a mix of pattern-matching, multi-clause functions and guard clauses.  

And though using control flow expressions may be easier to understand at first, as the complexity of a program increases, nested control structures can start to creep in.   Then we can simplify our code using the more functional patterns mentioned earlier.

There will definitely be times when you need to rely on Control Flow Expressions so it's worth understanding how they work.

Here's what we'll cover: if / unless; cond; case and with.

Versions

  • Elixir 1.10.0

if and unless

If you're familiar with Ruby, if and unless are used in the same way in Elixir.

if

5 is greater than 1 so the expression is true.

unless

unless will only execute the block when the expression results in nil or false:

Here the expression 5 > 1 is neither nil or false so the else clause is executed.

NOTE:  it's recommended to avoid using else with unless. Prefer if / else.

Inline

if and unless can also be used with the inline notation:

The else clause is optional. These examples will return nil if the main clause is falsy.

cond

The cond structure is known as a multi-way if statement where the code associated with the first truthy condition is executed.

This can be used as a replacement for if / else if statements.

Here's an example:


In this example, 1 is equal to 1 so the output was expected.

The last condition true serves as a default and will run when no other conditions are truthy.

case

case accepts an expression and works with the return value of the expression.  

It will pattern-match against the result from top to bottom running through the given patterns. Once a match is found, the code associated with it will run.

Let's start with a simple example:

Case Expression Result

Because case is an expression itself, it's designed to return a value.

File.read/1 returns {:ok, binary}, where binary is a binary data object that contains the contents of path, or {:error, reason} if an error occurs.

Here's an example:

We can now use the result of the case statement in our program.  Another contrived example, but it demonstrates that case is an expression.

with

with was introduced in Elixir 1.2 and can be used when a series of expressions need to be successful.  

with can also be used to replace nested case instances or even a group of multi-clause functions.

Here are some important flow concepts to understand when using with:

  • It accepts one or more expressions, a do block and an optional else clause.
  • It will pattern match on the return value of each expression and will only run the code in the do block when every pattern matches.
  • If one of the expressions do not have a match, it will return that expression's value.
  • If there is an else clause, this value will be return instead.

Let's use a real world example shared on twitter by @devoncestes simplified for readability:

Let's walk through this function remembering that each expression must have a match before the code in the do block will run:

  • a user must be found
  • a customer must be created
  • a subscription must be created
  • the user must be updated successfully

If every expression has a match the function return value will be: {:ok, :subscription_created}

Notice that no else clause was given.  This means that if any given expression doesn't have a successful match, its return value will be returned.

Wrapping Up

We've discussed the main control flow expressions in Elixir and used some examples to explore how they might be used.

Though it can be better to use a more functional programming style with multi-clause functions et al, there will inevitably be situations where using if / unless, cond, case or with makes more sense.

Troy Martin
Senior Engineer working with Elixir and JS.
Keep in the Loop

Subscribe for Updates

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.