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
While exceptional library is great, this partucular issue is fully covered by Elixir core Kernel.SpecialForms.with/1.
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
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}
Popular in Discussions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #javascript
- #code-sync
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








