Hi there !

This week at CodeBEAM I had a chance to meet an amazing crowd and participate in some interesting conversations. One of them was with more experienced with erlang folks discussing new `maybe_expr`

in OTP-25. @max-au raised concerns about it which I initially didnāt get right.

Iāve been happily writing elixir and using `with`

for years by now, thinking thatās the right way to handle cleanly the scenario of nested branching expressions with a single happy path. And for some reason I never questioned why `throw/catch`

is reserved as some sort of a ālast resortā for libs that donāt return :ok/:error tuples but `throw`

in error case.[*]

Also as mentioned in EEP-0049#Elixir

Elixir has a slightly different semantic approach to error handling compared to Erlang. Exceptions are discouraged for control flow (while Erlang specifically uses

`throw`

for it), and the`with`

macro is introduced

# Example:

Here, is the synthetic example that hopefully will help to show the idea:

Say I want to put together a function that does multiple things with given argument:

```
defmodule Foo do
def bar(num) do
num
|> double()
|> subtract(num)
|> divide(num)
|> multiply(num)
end
defp double(num), do: 2 * num
defp subtract(a, b), do: a - b
defp divide(a, b), do: a / b
defp multiply(a, b), do: a * b
end
```

Often in real world some of these private functions are expected to return erroneous resultsā¦ often we wrap the result in :ok and :error tuples and use `with`

special form.

Here is the example of the same module, but where each private function might return either :ok or :error tuple and parent function uses `with`

to focus on happy path and still be aware of possible erroneous results:

```
defmodule Foo do
@spec bar(number) :: {:ok, number} | {:error, :not_number | :zero_division}
def bar(num) do
with {:ok, double_num} <- double(num),
{:ok, subtracted_num} <- subtract(double_num, num),
{:ok, divided_num} <- divide(subtracted_num, num) do
multiply(divided_num, num)
end
end
defp double(x) do
if is_number(x),
do: {:ok, 2 * x},
else: {:error, :not_number}
end
defp subtract(a, b) do
if is_number(a) and is_number(b),
do: {:ok, a - b},
else: {:error, :not_number}
end
defp divide(_a, 0), do: {:error, :zero_division}
defp divide(a, b) do
if is_number(a) and is_number(b),
do: {:ok, a / b},
else: {:error, :not_number}
end
defp multiply(a, b) do
if is_number(a) and is_number(b),
do: {:ok, a * b},
else: {:error, :not_number}
end
end
```

However, we could have achieved the same behavior without need to wrap everything into āmonadicā :ok/:error tuples, just `throw`

when something goes wrong and let parent `catch`

it. As a bonus we can again use pipes (though, thatās not the priority point at this moment).

```
defmodule Foo do
@spec bar(number) :: number | :not_number | :zero_division
def bar(num) do
num
|> double()
|> subtract(num)
|> divide(num)
|> multiply(num)
catch
error -> error
end
defp double(x) do
if is_number(x),
do: 2 * x,
else: throw(:not_number)
end
defp subtract(a, b) do
if is_number(a) and is_number(b),
do: a - b,
else: throw(:not_number)
end
defp divide(_a, 0), do: throw(:zero_division)
defp divide(a, b) do
if is_number(a) and is_number(b),
do: a / b,
else: throw(:not_number)
end
defp multiply(a, b) do
if is_number(a) and is_number(b),
do: a * b,
else: throw(:not_number)
end
end
```

Apparently, this style is used in Erlang quite often.

Now Iām really puzzled, why it is discouraged in elixir?

[*] elixir-lang.org | Getting Started / Try, catch and rescue / Throws

Those situations are quite uncommon in practice except when interfacing with libraries that do not provide a proper API