Strange behaviour of Stream

Can someone tell me why the result of this snippet is an empty list?
The print out is after_fun: 1 which means there is an element in there isn’t it?

Stream.resource(
      fn ->
        []
      end,
      fn acc ->
        {:halt, acc ++ ["foo"]}
      end,
      fn acc ->
        IO.puts("after_fun: #{length(acc)}")
        acc
      end
    )
    |> Enum.to_list()

When you return :halt you can only update the accumulator, not the resulting stream of elements. You have to have at least one instance when you don’t return :halt.

Take you for taking time to answer my question. However I do not understand your explanation. Could you perhaps share with me how you would do this if you wanted to see ["foo"] in the final result

Sure. Sorry, my first answer was given in haste, I was on my phone.

Stream.resource(fn -> false end,
fn  # next_fun
  false -> {["foo"], true}
  true -> {:halt, :whatever}
end,
fn _ -> nil end)  # after_fun
|> Enum.to_list()
|> IO.inspect()

The accumulator is only used as internal state for next_fun and after_fun, and it’s not part of the output or directly visible to the caller of Stream.transform. When your next_fun returns {:halt, next_acc}, the stream ends and the output elements must have already been produced by previous calls to next_fun that returned {[elements], next_acc}, otherwise the output stream will be empty, which is what is going on in your example.

In other words: the accumulator has nothing to do with the elements, elements and accumulator are distinct entities.

2 Likes

Thank you for the detailed explanation. I got it now :slight_smile:

1 Like