7 Miscellaneous Features

7.1 Error Handling

Before we can handle errors we need to create them and the simplest way to do so is with raise/1:

iex> raise "Oh no!"
#> ** (RuntimeError) Oh no!

If we want to specify the type and message, we need to use raise/2:

iex> raise ArgumentError, message: "the argument value is invalid"
#> ** (ArgumentError) the argument value is invalid

When we know an error may occur, we can handle it using try/rescue and pattern matching:

try do
  raise "Oh no!"
rescue
  e in RuntimeError -> IO.puts("An error occurred: " <> e.message)
end
#> An error occurred: Oh no!
#> :ok

It’s possible to match multiple errors in a single rescue:

try do
  opts
  |> Keyword.fetch!(:source_file)
  |> File.read!()
rescue
  e in KeyError -> IO.puts("missing :source_file option")
  e in File.Error -> IO.puts("unable to read source file")
end

At times it may be necessary to perform some action after our try/rescue regardless of error. For this we have try/after.

try do
  raise "Oh no!"
rescue
  e in RuntimeError -> IO.puts("An error occurred: " <> e.message)
after
  IO.puts "The end!"
end
# An error occurred: Oh no!
# The end!
# :ok

This is most commonly used with files or connections that should be closed:

{:ok, file} = File.open("example.json")
try do
  # Do hazardous work
after
  File.close(file)
end

7.2 Sigils

7.2.1 ~r: regular expressions

iex > regex <- ~ r/foo|bar/
iex > "foo" <- ~regex
#> true
iex > "bat" <- ~regex
#> false

7.2.2 Strings, char lists and word list sigils

7.2.2.1 Strings

The ~s sigil is used to generate strings, like double quotes are. The ~s sigil is useful when a string contains double quotes:

iex> ~s(this is a string with "double" quotes, not 'single' ones)
#> "this is a string with \"double\" quotes, not 'single' ones"

7.2.2.2 Char lists

The ~c sigil is useful for generating char lists that contain single quotes:

iex> ~c(this is a char list containing 'single quotes')
#> 'this is a char list containing \'single quotes\''

7.2.2.3 Word lists

The ~w sigil is used to generate lists of words (words are just regular strings). Inside the ~w sigil, words are separated by whitespace.

iex> ~w(foo bar bat)
#> ["foo", "bar", "bat"]

The ~w sigil also accepts the c, s and a modifiers (for char lists, strings, and atoms, respectively), which specify the data type of the elements of the resulting list:

iex> ~w(foo bar bat)a
#> [:foo, :bar, :bat]

7.2.3 Calendar Sigils

7.2.3.1 Date

A %Date{} struct contains the fields year, month, day, and calendar. You can create one using the ~D sigil:

iex> d = ~D[2019-10-31]
#> ~D[2019-10-31]
iex> d.day
#> 31

7.2.3.2 Time

The %Time{} struct contains the fields hour, minute, second, microsecond, and calendar. You can create one using the ~T sigil:

iex> t = ~T[23:00:07.0]
#> ~T[23:00:07.0]
iex> t.second
#> 7

7.2.4 Custom Sigiils

As hinted at the beginning of this chapter, sigils in Elixir are extensible. In fact, using the sigil ~r/foo/i is equivalent to calling sigil_r with a binary and a char list as the argument:

iex> sigil_r(<<"foo">>, 'i')
#> ~r"foo"i

We can also provide our own sigils by implementing functions that follow the sigil_{character} pattern. For example, let’s implement the ~i sigil that returns an integer (with the optional n modifier to make it negative):

iex> defmodule MySigils do
...>   def sigil_i(string, []), do: String.to_integer(string)
...>   def sigil_i(string, [?n]), do: -String.to_integer(string)
...> end

iex> import MySigils
iex> ~i(13)
#> 13
iex> ~i(42)n
#> -42

Sigils can also be used to do compile-time work with the help of macros. For example, regular expressions in Elixir are compiled into an efficient representation during compilation of the source code, therefore skipping this step at runtime. If you’re interested in the subject, we recommend you learn more about macros and check out how sigils are implemented in the Kernel module (where the sigil_* functions are defined).