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
:
> raise "Oh no!"
iex#> ** (RuntimeError) Oh no!
If we want to specify the type and message, we need to use raise/2
:
> raise ArgumentError, message: "the argument value is invalid"
iex#> ** (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
in RuntimeError -> IO.puts("An error occurred: " <> e.message)
e 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
in KeyError -> IO.puts("missing :source_file option")
e in File.Error -> IO.puts("unable to read source file")
e 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
in RuntimeError -> IO.puts("An error occurred: " <> e.message)
e 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
> regex <- ~ r/foo|bar/
iex > "foo" <- ~regex
iex #> true
> "bat" <- ~regex
iex #> 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:
> ~s(this is a string with "double" quotes, not 'single' ones)
iex#> "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:
> ~c(this is a char list containing 'single quotes')
iex#> '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.
> ~w(foo bar bat)
iex#> ["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:
> ~w(foo bar bat)a
iex#> [:foo, :bar, :bat]
7.2.3 Calendar Sigils
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:
> sigil_r(<<"foo">>, 'i')
iex#> ~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):
> defmodule MySigils do
iex...> def sigil_i(string, []), do: String.to_integer(string)
...> def sigil_i(string, [?n]), do: -String.to_integer(string)
...> end
> import MySigils
iex> ~i(13)
iex#> 13
> ~i(42)n
iex#> -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).