Erlang and Elixir, Part 4: Control Flow

If, else, and logical operators are probably the most common similarity between the popular languages, and unsurprisingly Elixir has them, too. The if, case, and cond macros are provided for giving us control flow structure. 

For pattern matching, we mentioned before that using case provides matches against any pattern iteratively:

Worth noticing here is the _ case, which is essentially a default catch-all case. The case can be also used with an atom or any variable type like so.

Guard Clause Expressions

Elixir provides many operators to check in our expression as a guard against catching the wrong data. By default, the following are supported:

  • comparison operators (==!====!==>>=<<=)
  • boolean operators (andornot)
  • arithmetic operations (+-*/)
  • arithmetic unary operators (+-)
  • the binary concatenation operator <>
  • the in operator as long as the right side is a range or a list
  • all the following type check functions:
    • is_atom/1
    • is_binary/1
    • is_bitstring/1
    • is_boolean/1
    • is_float/1
    • is_function/1
    • is_function/2
    • is_integer/1
    • is_list/1
    • is_map/1
    • is_nil/1
    • is_number/1
    • is_pid/1
    • is_port/1
    • is_reference/1
    • is_tuple/1
  • plus these functions:
    • abs(number)
    • binary_part(binary, start, length)
    • bit_size(bitstring)
    • byte_size(bitstring)
    • div(integer, integer)
    • elem(tuple, n)
    • hd(list)
    • length(list)
    • map_size(map)
    • node()
    • node(pid | ref | port)
    • rem(integer, integer)
    • round(number)
    • self()
    • tl(list)
    • trunc(number)
    • tuple_size(tuple)

We can use them like so:

Additionally, an anonymous function can have multiple guards. For example, to calculate a pivot point from a financial market data using the high, low, and close values, we can do this:

Here, if the high value is less than low, the pivot anonymous function will return an Error message. This one-line fashion of writing guards is phenomenally powerful.


Like a switch statement, Elixir's cond is where we can perform a string of if else like blocks and execute on the match.

Inside a cond block, everything is evaluating to true except nil or false. That's all numerical values and strings included. 

For example, we can check the current status for various possibilities with a cond block:

When the value of status is set to a string, it will evaluate; otherwise, an error message will be output by default via the last true case.

If and Unless

Elixir also provides us with unless, which is a default part of the if else block and can be demonstrated as so:

When the if case evaluates as true, unless will allow you to have access to the opposite. As demonstrated, we can catch the other side of the conditional this way.

In a real-life example, this can be used for displaying conditional information during a conditional check, such as a reminder or hint. 

Do/End Blocks

Throughout these examples, we have seen the usage of the do and end macros. Let's have a closer look at them now before we conclude this section:

The comma after true is for Elixir's regular syntax, where each argument is comma-separated. This syntax uses keyword lists, and when used in conjunction with the else macro it will look like this:

To make this nicer for development, we can use the do/end block, which does not require the comma for a direct approach:


Elixir has the familiar control flow structures if/else and case, and it also has unless and the do/end block.

We can achieve any logic via manipulation of control flow with these structures. When you use them in conjunction with macros, anonymous functions, and modules, you have a great supply of options to get the work done. 

For continued reading on the topic, the manual provides more insights into some of the further caveats of using the do/end block, such as function scope limitations. 

Source: Tuts Plus

About the Author