windexoriginal
Collectable for error tuple, a good idea?
I often find myself with code like this when applying a function that returns error tuples to an enumerable:
is_ok? = fn x ->
if x < 5, do: {:ok, x}, else: {:error, "too big"}
end
Enum.reduce_while(1..5, {:ok, []}, fn v, {:ok, vs} ->
case is_ok?.(v) do
{:ok, v} -> {:cont, {:ok, [v | vs]}}
{:error, _} = e -> {:halt, e}
end
end)
But, if I write a simple collectable implementation for Tuple, I can write this instead:
for x < - 1..5, into: {:ok, []}, do: is_ok.(x)
I much prefer the second: it’s short, it’s clear, and I don’t mind too much that it iterates the whole enumerable every time. Is implementing a protocol for convenience on a built in type like this a good long term decision?
Most Liked
FlyingNoodle
I much, much prefer the first version. I can immediately see what happens and understand.
I always prefer clarity over brevity. Always. Every. Single. Time.
al2o3cr
My reading was that the Collectable implementation would check the shape of the block’s return value:
- if it’s
{:ok, value}and the accumulator is{:ok, values}then the new accumulator is{:ok, values ++ [value]}(or equivalent with reverse-at-the-end for performance) - if it’s
{:ok, value}and the accumulator is anything else then the new accumulator is unchanged - if it’s
{:error, e}then the new accumulator is{:error, e}
I don’t think I’d personally choose this approach, since it requires defining Collectable for all tuples but only actually cares about specific shapes








