dimroc
dimroc

Reputation: 1194

Stream.into + Stream.run identical to Enum.into?

Elixir allows you to use Streams instead of Enums 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

Answers (1)

Patrick Oscity
Patrick Oscity

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

Related Questions