danj

danj

Conditional pipe operator on error tuple

I wanted to share this code for a problem that regularly comes up and that I usually solve with multi-headed functions or with clauses. The issue: handling an error tuple in a pipeline situation by skipping steps.

Here’s the code: (Important: There’s a bug in this macro, see below)

  defmacro left ~> right do
    quote do
      case unquote( left ) do
        { :error, _ } = err -> err
        val -> unquote( Macro.pipe( left, right, 0 ) )
      end
    end
  end

Which makes possible a pipeline that looks like:

start_value
|> step_a
~> step_b
~> step_c
|> step that handles  { :error, _ } or a real result

Any thoughts on this approach?

Dan

Most Liked

mudasobwa

mudasobwa

Creator of Cure

While exceptional library is great, this partucular issue is fully covered by Elixir core Kernel.SpecialForms.with/1.

OvermindDL1

OvermindDL1

That’s pretty common, what what the exceptional library on hex.pm does (it handles raw values, tagged ok/error tuples, returning exceptions, multiple styles of handling errors, etc…). I use it quite a lot.

danj

danj

This is the Kernel.|>/2 macro sequence. It felt a little unsatisfying knowing it translates into Macro.pipe. With a little more time and testing it seems to cleanly reduce to:

unquote( Macro.pipe( (quote do: val), right, 0 ) )

A simple test looking like:

iex(101)> 14+7 ~> IO.inspect(label: 1) |> IO.inspect( label: 2) ~> IO.inspect( label: 3 ) |> IO.inspect( label: 4 )
case(14 + 7 ~> IO.inspect(label: 1) |> IO.inspect(label: 2)) do
  {:error, _} = err ->
    err
  val ->
    IO.inspect(val, label: 3)
end
case(14 + 7) do
  {:error, _} = err ->
    err
  val ->
    IO.inspect(val, label: 1)
end
1: 21
2: 21
3: 21
4: 21
21

The code printing comes from an inline Macro.to_string( ast ) for illustration. The code shows backward since the unpipe rolls the pipe up in reverse while nesting.

This is the error tuple scenario:

iex(102)> { :error, 14+7 } ~> IO.inspect(label: 1) |> IO.inspect( label: 2) ~> IO.inspect( label: 3 ) |> IO.inspect( label: 4 )
case({:error, 14 + 7} ~> IO.inspect(label: 1) |> IO.inspect(label: 2)) do
  {:error, _} = err ->
    err
  val ->
    IO.inspect(val, label: 3)
end
case({:error, 14 + 7}) do
  {:error, _} = err ->
    err
  val ->
    IO.inspect(val, label: 1)
end
2: {:error, 21}
4: {:error, 21}
{:error, 21}

Where Next?

Popular in Discussions Top

MarioFlach
Hello, I want to share a project I’ve been working on for a while: https://github.com/almightycouch/gitgud Background Some time ago I ...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
sashaafm
Piggy backing a bit on @dvcrn topic BEAM optimization for functions with static return type?, I’ve been trying to understand in a deeper ...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39297 209
New
AstonJ
I’ve just started the Phoenix part of the utterly brilliant online course by @pragdave. On generating the Phoenix app he uses the --no-ec...
New
New
jer
I’ve been using umbrellas for a while, and generally started off (on greenfield projects at least) by isolating subapps based on clearly ...
New
acrolink
How does the two languages compare when it comes to server side application development? Any experiences or ideas? Thank you.
New
joeerl
I’m playing with Elixir - It’s fun. I think @rvirding does give Elixir courses these days. Re: files and database - when I given Erlang ...
New
Markusxmr
Since Drab has been developed for a while in the open, introducing the Liveview functionality in a way it happend appears to undermine th...
New

Other popular topics Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
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