Errors in Elixir

In Elixir, error handling is typically done using pattern matching and the {:ok, result} or {:error, reason} tuple convention. This differs from Go’s explicit error return values but serves a similar purpose.

defmodule ErrorExample do
  # By convention, functions that can fail return {:ok, result} or {:error, reason}
  def f(arg) do
    if arg == 42 do
      # Return an error tuple
      {:error, "can't work with 42"}
    else
      # Return a success tuple
      {:ok, arg + 3}
    end
  end

  # Define custom error atoms (similar to sentinel errors in Go)
  @out_of_tea :out_of_tea
  @power_failure :power_failure

  def make_tea(arg) do
    case arg do
      2 -> {:error, @out_of_tea}
      4 -> {:error, {:power_failure, "can't boil water"}}
      _ -> {:ok, "Tea is ready!"}
    end
  end

  def run do
    # Demonstrate error handling with pattern matching
    Enum.each([7, 42], fn i ->
      case f(i) do
        {:ok, result} -> IO.puts("f worked: #{result}")
        {:error, reason} -> IO.puts("f failed: #{reason}")
      end
    end)

    # Demonstrate error handling with custom errors
    Enum.each(0..4, fn i ->
      case make_tea(i) do
        {:ok, message} ->
          IO.puts(message)
        {:error, @out_of_tea} ->
          IO.puts("We should buy new tea!")
        {:error, {:power_failure, reason}} ->
          IO.puts("Now it is dark: #{reason}")
        {:error, reason} ->
          IO.puts("Unknown error: #{inspect(reason)}")
      end
    end)
  end
end

ErrorExample.run()

In Elixir, we use pattern matching to handle different outcomes, including errors. The case statement is often used to match on the returned tuples and handle success and error cases.

Elixir doesn’t have a built-in error type like Go’s error interface. Instead, it uses atoms or tuples to represent errors. Custom errors can be defined as atoms or structured tuples for more complex error information.

The inspect/1 function is used to convert any term to a string representation, which is useful for printing complex error structures.

To run this program, save it as error_example.exs and execute it with:

$ elixir error_example.exs
f worked: 10
f failed: can't work with 42
Tea is ready!
Tea is ready!
We should buy new tea!
Tea is ready!
Now it is dark: can't boil water

This example demonstrates how Elixir handles errors using pattern matching and the tuple convention, which provides a clean and expressive way to manage and propagate errors throughout your application.