Luís Soares
Luís Soares

Reputation: 6222

What is the advantage of using Elixir's "with"

I saw this code at the Elixir School:

with {:ok, user} <- Repo.insert(changeset),
     {:ok, token, full_claims} <- Guardian.encode_and_sign(user, :token, claims) do
  important_stuff(token, full_claims)
end

I don't get the difference to simply:

{:ok, user} <- Repo.insert(changeset),
{:ok, token, full_claims} <- Guardian.encode_and_sign(user, :token, claims)
important_stuff(token, full_claims)

Upvotes: 0

Views: 52

Answers (1)

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121010

{:ok, user} <- Repo.insert(changeset) without with would raise (CompileError) undefined function <-/2 in the first place. You probably meant {:ok, user} = Repo.insert(changeset).

Kernel.SpecialForms.with/1 plays the role of Either monad to some extent.

If RHO matches to LHO, it goes to the next clause. Otherwise, it immediately early returns the non-matched RHO, discarding all the other clauses. Consider several functions that should be applied sequentially, if and nobly if the previous one succeeds. Somewhat along these lines.

with {:ok, text} <- File.read(name),
     {:ok, words} <- MyStemmer.get_words(text),
     count when in_integer(count) <- Enum.count(words),
  do: IO.puts("File contained #{count}" words)

If there is no such file, the whole snippet would return {:error, :enoent} because the very first clause would fail to pattern match LHO.

{:ok, text} = File.read(name) would instead raise MatchError when there is no such file.


I have written a blog post on the subject three years ago, it might be still worth reading.

Upvotes: 3

Related Questions