Beginner's Track: With
or
Within You Without You

Before we get with it...
- In Elixir, the = operator is actually called the match operator
- A common example you may see:
A quick pattern matching review
iex> {:ok, result} = {:ok, 13}
{:ok, 13}
iex> result
13More pattern matching...
iex> x = 1
1
iex> x
1
iex> 1 = x
1
iex> 2 = x
** (MatchError) no match of right hand side value: 1
iex> {:ok, result} = {:ok, 13}
{:ok, 13}
iex> result
13Almost `with` it...A quick review of pipes
- I'm hoping you have some experience with Unix pipes as these are similar.
- From the docs, "The `|>` symbol...is the pipe operator:
- it takes the output from the expression on its left side and passes it as the first argument to the function call on its right side." [4]
- They allow the ability to "stream" from one operation to the next.
Pipes example
1..500 |>
Enum.map(fn x -> x / 2 end) |>
Enum.filter(fn x -> x > 200 end) |>
Enum.countWhat is with?
- The `with` operator is a control flow mechanism that allows a sequence of operations to return a value or the ability to break out of that sequence.
- It allows you to match on differing results, enabling you (similar to pipes) build a functional sequence
Examples
Let's look at some examples from Jose:
with {:ok, x} <- ok(1),
{:ok, y} <- ok(2),
do: {:ok, x + y}
#=> {:ok, 3}If they all match in the sequence, we're done.
with {:ok, x} <- ok(1),
{:ok, y} <- error(2),
do: {:ok, x + y}
#=> {:error, 2}Here, because they don't, the sequence is aborted and an error is returned.
Why use with?
- Error handling
def handle_request(request) do
with {:ok} <- validate_request(request),
{:ok, user} <- get_user(request),
{:ok} <- update_db(user),
{:ok} <- send_email(user) do
return_http_message
else
{:error, reason} -> handle_error(reason)
_ -> handle_ambigous_error
# alternately, you could handle the errors
# {:error, :update_db, details} -> handle_update_db_error(details)
# {:error, :send_email, details} -> handle_send_email_error(details)
end
end Why use with?
- Chainable with multiple outputs
opts = %{width: 10, height: 15}
assert {:ok, 150} ==
with {:ok, width} <- Map.fetch(opts, :width),
{:ok, height} <- Map.fetch(opts, :height),
do: {:ok, width * height}Why use with?
- Handle ugly case statement nesting
case File.read(path) do
{:ok, binary} ->
case :beam_lib.chunks(binary, :abstract_code) do
{:ok, data} ->
{:ok, wrap(data)}
error ->
error
end
error ->
error
endwith {:ok, binary} <- File.read(path),
{:ok, data} <- :beam_lib.chunks(binary, :abstract_code),
do: {:ok, wrap(data)}Can become:
With (or without with)
By ralucas
With (or without with)
- 332