Range Over Channels in Elixir

In a previous example, we saw how for and comprehensions provide iteration over basic data structures. We can also use similar syntax to iterate over values received from a channel.

defmodule RangeOverChannels do
  def main do
    # We'll iterate over 2 values in the `queue` channel.
    queue = Channel.new(2)
    Channel.send(queue, "one")
    Channel.send(queue, "two")
    Channel.close(queue)

    # This `receive` loop iterates over each element as it's
    # received from `queue`. Because we closed the
    # channel above, the iteration terminates after
    # receiving the 2 elements.
    for elem <- Channel.stream(queue) do
      IO.puts(elem)
    end
  end
end

RangeOverChannels.main()

When you run this program, you’ll see:

$ elixir range_over_channels.exs
one
two

This example also showed that it’s possible to close a non-empty channel but still have the remaining values be received.

In Elixir, we don’t have built-in channels like in some other languages. Instead, we’re using a hypothetical Channel module to simulate similar behavior. The for comprehension with Channel.stream(queue) is used to iterate over the channel’s values.

The concept of ranging over channels is similar to using Stream.resource/3 in Elixir for creating a stream from a stateful resource. In practice, you might use Elixir’s built-in concurrency primitives like processes and message passing to achieve similar functionality.