Channel Directions in Elixir

In Elixir, we can specify the direction of data flow in function parameters using the send_only and receive_only modifiers. This specificity increases the type-safety of the program.

defmodule ChannelDirections do
  # This `ping` function only accepts a channel for sending
  # values. It would be a compile-time error to try to
  # receive on this channel.
  def ping(pings, msg) do
    send(pings, msg)
  end

  # The `pong` function accepts one channel for receives
  # (pings) and a second for sends (pongs).
  def pong(pings, pongs) do
    receive do
      msg -> send(pongs, msg)
    end
  end

  def main do
    pings = spawn_link(fn -> receive_loop() end)
    pongs = spawn_link(fn -> receive_loop() end)

    ping(pings, "passed message")
    pong(pings, pongs)

    receive do
      msg -> IO.puts(msg)
    end
  end

  defp receive_loop do
    receive do
      msg -> send(self(), msg)
    end
    receive_loop()
  end
end

ChannelDirections.main()

To run the program:

$ elixir channel_directions.exs
passed message

In this Elixir version, we use processes and message passing to simulate channels. The ping and pong functions send messages to processes, and we use receive blocks to handle incoming messages.

The main function creates two processes (pings and pongs) that act as our channels. We then call ping and pong with these processes, and finally, we wait to receive and print the final message.

Note that Elixir doesn’t have built-in channel direction specifications like Go does. However, the actor model and message passing in Elixir provide a similar level of concurrency control.