Pattern match in with clause 🤯

twitter logo github logo Originally published at til.ryanwill.dev on ・1 min read

I had a problem where I needed to make sure a string was returned from a function that was part of a with clause. I thought, “You can’t pattern match here, right? That would just be too convenient.”

Turns out you totally can. Here’s an example from the docs.

users = %{"melany" => "guest", "bob" => :admin}

with {:ok, role} when not is_binary(role) <- Map.fetch(users, "bob") do
  {:ok, to_string(role)}
twitter logo DISCUSS (1)
markdown guide

This is why the with syntax is so awesome.

If your pattern match fails, it tries to pattern match in the else block too, which allows you to handle all of your errors below, and all of your happy paths above, so at a glance it's clear what your intent is.

This is also basis to another really interesting pattern that I've really come to like - tagged tuple.

Sometimes your pattern matching might return something pretty generic, so it's hard for you to handle the errors for them, for example:

data = "a"
with true <- is_binary(a),
         true <- a == "a" do
  false ->
     # here you handle the error, but you don't know which one of the function fails.

Tagged tuple changes this, by wrapping each execution in a tuple, like this:

data = "a"
with {:string, true} <- {:string, is_binary(a)},
         {:a, true} <- {:a, a == "a"} do
   # now you can handle specific errors
   {:string, false} ->
   {:a, false} ->


I have an example running in the wild here:


You can see how elegant error handling gets!

Classic DEV Post from Jun 30 '19

What is your favourite Git command?

Ryan Will profile image
Cultivating software. Aprendiendo español. Piensa más en lo que te fascina.