Another alternative is to have a function that forwards everything that is 
not :ok, and does something with {:ok, value} responses:

  defp if_ok(input, fun) when is_function(fun) do
    input
    |> case do
      {:ok, content} ->
        case fun.(content) do
          # if function does not return a tuple, but a map, make it {:ok, 
res}
          res = %{} -> {:ok, res}
          other -> other
        end
      other -> other
    end
  end
  defp if_ok(input, value) do
    if_ok input, fn (_) -> value end
  end

Then you could chain in the following way

    do_something
    |> if_ok(&Repo.delete/1)
    |> if_ok(&AlgoliaService.delete_content_item/1)
    |> if_ok(&broadcast_content_item_removed/1)
    |> if_ok(:ok)

Can read a bit nicer than with, and easier to implement in existing 
pipeline. Still quite clean imo.

Cheers,

Jaap

On Monday, August 15, 2016 at 7:29:59 PM UTC+8, alco wrote:
>
> The Elixir way is to use the pipe and `with` where each is more suitable 
> for the task. So if you need to write a sequence of function calls where 
> some or all are expected to return an error, `with` would be the most 
> appropriate tool to use.
>
> One key difference between a pipeline and `with` is that the latter stops 
> evaluation as soon as it encounters the first failed match. Whereas with a 
> pipeline you'd have to wrap all constituent functions to pass the error 
> from a previous step down to the next one. I see it as a downside to trying 
> to use the pipe in places where it is more important to explicitly handle 
> errors.
>
> On Mon, Aug 15, 2016 at 2:12 PM, Alvise Susmel <[email protected] 
> <javascript:>> wrote:
>
>> Hi, 
>>
>> I've started thinking about this, as maybe many of you, when I needed to 
>> stop the pipe when an error is returned. I've seen that there are different 
>> conversation about this, but I haven't clear what is the *elixir way* to 
>> handle errors using pipes. 
>>
>> I see two ways for achieving the same result.* The first* is to use the 
>> *pipe* *|>* and for each function catch the error and propagate it down. 
>> The error has to be always returned with the same pattern, like {:error, 
>> reason} 
>>
>> connect
>> |> receive_image
>> |> resize
>> |> rotate
>> |> save
>>
>>
>> If *receive_image* returns an error,  *resize* needs to handle it
>>
>> def resize({:error, _}=error), do:error
>>
>> and to propagate it down through the pipe. So *rotate* needs to do the 
>> same, etc..
>>
>> *The* *second* way I see is using the *with*, which to me seems to be 
>> more generic (and less clean)
>>
>> with {:ok, pid} <- connect,
>>        {:ok, image} <- receive_image(pid),
>>        {:ok, resized_image} <- resize(image),
>>       {:ok, rotated_image} <- rotate(resized_image),
>>       :ok <- save(rotated_image)
>> do: IO.puts "saved"
>>
>>
>> Now, the cool thing about *with* is that when one of the assignments 
>> fails, it exits returning the value that failed the pattern match. 
>>
>> So, to you, what is the elixir way on handling the return errors on pipes 
>> ? Could *"with" *be seen as a new (and more generic) way of piping with 
>> error handling ?
>>
>> Thanks
>>
>> Alvise
>>
>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "elixir-lang-core" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to [email protected] <javascript:>.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/elixir-lang-core/1dc86df2-eca0-4fa5-b883-7b9c2df36444%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/elixir-lang-core/1dc86df2-eca0-4fa5-b883-7b9c2df36444%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/4f0835a1-790a-4b1e-9dad-ed593292bc37%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to