Crowdhailer

Crowdhailer

Creator of Raxx

Add error binding to function definitions, Experimental

This example overrides Kernel.def/2, so I am aware it is only suitable as an experiment. However here are the results.

Given the functions fetch_user and fetch_cart that both return {:ok, value} or {:error, reason}.

defmodule MyApp do
  use OK.Kernel

  def checkout(user_id, cart_id) do
    user <- fetch_user(user_id)        # `<-` will bind user when fetch_user returns {:ok, user}
    cart <- fetch_cart(cart_id)        # `<-` will shortcut to else clause if returned {:error, reason}
    order = checkout(cart, user)       # Lines without `<-` behave normally

    order.invoice_id
  else
    :user_not_found ->
      IO.puts("No user for user_id: #{user_id}")
      nil
    :cart_not_found ->
      IO.puts("User has no cart")
      nil
  end

end

By using OK.Kernel errors can be grouped in what I consider to be a very natural way.
I guess it’s natural because it looks like how I would arrange raise and catch in previous languages. However with the magic of Elixir macros I can do it all without using exception raising.

To try it yourself add the release candidate to your mix.exs

{:ok, "~> 1.7.0-rc.1"}

Comments welcome.

My motivation for trying this was to separate unhappy paths due to code errors ( I still raise exceptions for them) and the unhappy path due to bad input.

Most Liked

aseigo

aseigo

Personally, I think this leads to hard to reason about code due to the loss of locality between the function body and the else that may or may not be triggered. It’s the same reason goto is “considered harmful” (caveats and exceptions to that aside :slight_smile: )

This feels like a place where with would be a good solution. A bit of syntatic sugar around it to tease the behavior of with to automatically succeed on {:ok, anything} and fail on {:error, anything} would be nicer imho, and iirc someone recently did exactly that.

Also, I find that if I have long(er) functions where there are conditions somewhere in the middle that need to branch, such as on failure or success, that this is a signal that perhaps I should break that function there and send processing on to another function which will continue on success or return on failure.

IOW, each function goes as far as it can until need to react to a success/failure and at that point calls another function. So each function ends up being a bit-sized bit of code that does execute completely, allowing each function to be reasoned about simply and clearly.

Exceptions (or, what they really are: early returns) are a tool of “last resort” for me, used when they are really required only. Similarly for case/with/etc. If those start nesting, or a function ends up being a series of them, I take that as a code smell to start chopping that function up into more atomic sets of code to stuff into functions.

Where Next?

Popular in Announcing Top

dbern
I’m excited to announce that TaxJar has developed and open-sourced DateTimeParser. We developed it because we found a need to parse user ...
New
mplatts
With HEEX released we decided to start a components library using Tailwind CSS - check it out here: Petal Components. We also have a boi...
New
oltarasenko
Dear Elixir community, After a year of development, bug fixes, and improvements, we are proudly ready to share the release of Crawly 0.1...
New
michalmuskala
Another small library today. PersistentEts Hex: persistent_ets | Hex GitHub: GitHub - michalmuskala/persistent_ets · GitHub Ets table ...
New
Flo0807
Hello everyone! I am excited to share our heart project Backpex with you. After building several Phoenix applications, we realized that...
New
josevalim
Hello everyone, We have just released NimbleCSV which is a small and fast CSV parsing library for Elixir. It allows developers to define...
New
achempion
Hi, I would like to tell about my initiative to further maintain and develop Waffle project which is the fork of Arc library. The progre...
New
marcuslankenau
I feel kind of stuck with the absence of a proper xml library for Elixir. Currently I use SweetXML which was ok for me more or less to pa...
New
zoltanszogyenyi
Hey everyone :waving_hand: Excited to join this forum - I am one of the founders and current project maintainers of a popular and open-s...
New
kevinlang
Hey all, We have made an Ecto3 Adapter for SQLite3, ecto_sqlite3! We have successfully on-boarded the full suite of integration tests (...
New

Other popular topics Top

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
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 41539 114
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement