Crowdhailer

Crowdhailer

Creator of Raxx

OK - elegant error handling with result monads (alternative to Elixir `with` special form)

Experimenting with this code.

OK.try do
  user <- fetch_user(1)
  cart <- fetch_cart(1)
  order = checkout(cart, user)
  save_order(order)
end

Ok.with/1 supports an else block that can be used for handling error values.

OK.with do
  a <- safe_div(8, 2)
  _ <- safe_div(a, 0)
else
  :zero_division -> # matches on reason
    {:ok, :inf}     # must return a new success or failure
end

The cart example above is equivalent to

with {:ok, user} <- fetch_user(1),
     {:ok, cart} <- fetch_cart(1),
     order = checkout(cart, user),
     {:ok, order_id} <- save_order(order)
do
   {:ok, order_id}
end

I have an implementation marked as beta as part of my OK project.

The Elixir with keyword has been very helpful for handling code with lots of branches, normally many error conditions. Such as the example above.

In the with example I find it is strange that the majority of my code my code lives in a list of arguments. It starts to get very lumpy if there are receive blocks or anonymous functions to get these values. Also in 90% of cases I am matching on an :ok tuple so don’t want to repeat that.

For these reasons I have been using the alternative macro from OK. It is far more restrictive because it will only match on :ok/:error tuples. However I like the restriction because it means that no matter how complex the block it will also only return :ok/:error tuples.
I am not sure that try is the best name. Alternatives that I am considering are

  • when, seams so make sense linguistically but already a keyword in elixir
  • with, familiar to elixir users
  • for, monadic for comprehension which is what this is but that might not be a very accessible term.
  • try, As is, however it doesn’t catch errors so the name could be misleading

Most Liked

ibgib

ibgib

I like OK.with because

  1. It let’s regular elixir users immediately grok that it’s like with.
  2. It’s idiomatic English! “I’m OK with that.”

(Try sounds like a try/catch/rescue replacement as opposed to a with replacement)

chrismccord

chrismccord

Creator of Phoenix

This is a great lib for playing with macros! That said, I’m personally :thumbsdown: on efforts around alternatives to with, as I haven’t seen justified benefits.

It’s worth pointing out that you should call out to functions in those cases. Also where you are seeing repetition, I am seeing explicit matching. The issues with Ok is that is hides the true match, and it gets more confusing if you were include a match within the 2nd elem, i.e. %{key: val} <- .... Is the rhs returning a tuple or map? It also breaks down the moment you want to match on something not in an :ok tuple. Using with, you simply add a new clause, with Ok you need to rewrite the entire block.

Crowdhailer

Crowdhailer

Creator of Raxx

Version 1.10.0: Add map/2 and ~> to treat result tuples as Functors.

The latest version of ok (1.10.0) has been release. It adds functionality to transform a value within an :ok tuple. e.g.

Examples

iex> {:ok, 5} ~> Integer.to_string
{:ok, "5"}

iex> {:error, :zero_division_error} ~> Integer.to_string
{:error, :zero_division_error}

iex> {:ok, "a,b"} ~> String.split(",")
{:ok, ["a", "b"]}
Crowdhailer

Crowdhailer

Creator of Raxx

Version 1.6.0 released, with two main improvements.

  • Much better errors, showing code snippet, expected and actual values

      Binding to variable failed, '{:bad, 6}' is not a result tuple.
    
      Code
        b <- bar(a)
    
      Expected signature
        bar(a) :: {:ok, b} | {:error, reason}
    
      Actual values
        bar(a) :: {:bad, 6}
    
  • required/2 to turn nilable values to result tuples

      maybe_port = Map.get(config, :port)
      {:ok, port} | {:error, :port_number_required} = OK.required(maybe_port, :port_number_required)
vic

vic

Asdf Core Team

Searching happy path brought me here :D, turns out, I was experimenting with topics like this some time ago, actually some of my first macro libraries are either similar to Ok or explore something along the lines.

  • ok_jose
    This one was my first macro library, I just wanted a result monad, you know for piping ok tagged tuples. But one of my main focus was not to introduce (nor override) existing |> elixir operators.
    Mostly like Ok and also allowed you to define other patterns besides :ok/:error tagged tuples.
    See the defpipe on the README, for example
@doc "Pipes a valid changeset or its ok tagged tuple"
defpipe pipe_valid_changeset do
   valid = %Ecto.Changeset{valid?: true) -> valid
   {:ok, record} -> record
end

# then you can pipe functions that expect valid changesets
{:ok, %User{}}
|> cast(params, [:email, :password])
|> validate_password_conformation()
|> Repo.create
|> new_user_token()
|> pipe_valid_changeset() # no new syntax, just this guy rewrites the pipe
  • happy
    Then for cases that were code was not that homogeneous (not always returning :ok/:error tagged tuples) I just wanted to avoid lots of nested case and ended up doing something along the lines of with (back before it landed in Elixir 1.2, which I’ve been pretty much happy_with, except for its commas between match expressions)

  • pit
    This one is a bit weird (most things I do are), it was an experiment for having a with made for pipes. That is, you could specify a foo() |> pit(value <- pattern) |> bar() and let bar() take the value from the pattern matched result from foo.

Anyways, I guess it’s an interesting topic, and looks like for others too, since we have some people crafting this kind of things that do similar things (see the ones linked on Ok's README), if you find any other similar, I’d be interested in looking at it. :slight_smile:

BTW, great work on Ok @Crowdhailer, I’d go for OK.with since it’s closer to what with does and when reminds me of guards.

Where Next?

Popular in Libraries Top

Qqwy
Solution is a library to help you with working with ok/error-tuples in case and with-expressions by exposing special matching macros, as ...
New
wojtekmach
Hey everyone! Req is an HTTP client for Elixir that I’ve been working on for quite some time. There is already a lot of HTTP clients out...
New
cjen07
parameterized pipe in elixir: |n&gt; edit: negative index in |n&gt; and mixed usage with |&gt; are supported example: use ParamP...
New
pkrawat1
Hey guyz We at @aviabird are working on a payment library in elixir/phoenix. We are targeting March 2018 to add 56 Gateways to it. Have...
New
sasajuric
I’d like to announce a small library called boundaries. This is an experimental project which explores the idea of enforcing boundaries ...
New
treble37
Just looking for a little feedback on a tiny helper library I built - Sometimes I find the need to convert maps with atom keys to maps...
New
mbuhot
Leverage Open Api 3.0 (Swagger) to document, test, validate and explore your Plug and Phoenix APIs. Generate and serve a JSON Open API ...
New
michalmuskala
Another small library today. PersistentEts Hex: persistent_ets | Hex GitHub: GitHub - michalmuskala/persistent_ets Ets table backed by...
New
tmbb
I’ve published the first version of my Makeup library. It’s a syntax highlighter for Elixir in the spirit of Pygments, Currently it highl...
New
Crowdhailer
Experimenting with this code. OK.try do user &lt;- fetch_user(1) cart &lt;- fetch_cart(1) order = checkout(cart, user) save_or...
New

Other popular topics Top

Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
sergio
I couldn’t find any guides that worked well with Phoenix 1.6.0 and esbuild. I hope this helps people test the waters and eases you into t...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
AstonJ
by Lance Halvorsen Elixir and Phoenix are generating tremendous excitement as an unbeatable platform for building modern web application...
460 27162 124
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New

Sub Categories:

We're in Beta

About us Mission Statement