In Elixir, it is very common to use blocks of code processed with with
.
We go through all the executions in the indicated order.
The first mismatch with the expected pattern ends the processing.
The expression handler then begins.
Sometimes, however, there are problems in how to indicate which case took place. It is especially true when multiple functions return similar responses. See an example of checking access permissions:
1
2
3
4
5
6
7
8
9
with true <- is_active?(user),
true <- can_use_premium_feature?(user),
...
do
...
else
false -> {:error, "User deactivated or premium features disabled"}
...
end
In the situation indicated above, it is difficult to tell which of the functions is_active?/1
or can_use_premium_feature?/1
returned false
.
However, by using tuple-wrapping, we can have better execution control.
Such code is much clearer when handling errors, and we can also indicate more precise information.
Compare both solutions:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
with {:active, true} <- {:active, is_active?(user)},
{:can_use_premium, true} <- {:can_use_premium, can_use_premium_feature?(user)},
...
do
...
else
{:active, false} ->
{:error, "User deactivated"}
{:can_use_premium, false} ->
{:error, "Premium features disabled"}
...
end
You don’t need to modify the response from the function is_active?/1
nor can_use_premium_feature?/1
.
It can be super handy if the code is used in multiple places.