Reputation: 1194
Elixir allows you to use Stream
s instead of Enum
s to prevent intermediary copies of collections. But when you're on the last step, would it even matter?
Even when you get to the smallest details isn't this
Stream.concat(header, rows)
|> CSV.encode
|> Stream.into(output)
|> Stream.run
the same as this?
Stream.concat(header, rows)
|> CSV.encode
|> Enum.into(output)
If so, why would the Stream.into/3
docs advocate the pairing of Stream.into
+ Stream.run
and not just say Enum.into
?
Perhaps it's a simple as just being more readable and discoverable.
Upvotes: 4
Views: 467
Reputation: 54674
Your two examples don't really do the same thing. The first one just runs the stream pipeline, while the second one will also give you a return value. Since you are not using the result, Stream.run
is just fine in this case.
Generally, if you're interested in the result of a stream you can always use the Enum
counterparts in the last step of a pipeline. Stream.run
will not return the results, but rather apply the pipeline and then return :ok
. This is useful if you're interested in the side effects rather than the actual return value.
I suppose the reason we have Stream.into
as well is that it might not actually be the last step in the pipeline. Here's a contrived example:
output = IO.stream(:stdio, :line)
Stream.iterate(0, &(&1 + 1))
|> Stream.chunk(2, 1)
|> Stream.into(output, &"BEFORE: #{inspect &1}\n")
|> Stream.map(fn [x, y] -> x * y end)
|> Stream.into(output, &"AFTER: #{inspect &1}\n")
|> Stream.take(3)
|> Stream.run
Which will output
BEFORE: [0, 1]
AFTER: 0
BEFORE: [1, 2]
AFTER: 2
BEFORE: [2, 3]
AFTER: 6
Upvotes: 7