Channel Directions in Ruby

Ruby’s approach to channel-like communication is different from Go’s, but we can achieve similar functionality using Ruby’s Thread and Queue classes. Here’s an equivalent implementation:

require 'thread'

# This `ping` method only accepts a queue for sending
# values. It would be a runtime error to try to
# receive from this queue within this method.
def ping(pings, msg)
  pings.push(msg)
end

# The `pong` method accepts one queue for receives
# (`pings`) and a second for sends (`pongs`).
def pong(pings, pongs)
  msg = pings.pop
  pongs.push(msg)
end

# Main execution
pings = Queue.new
pongs = Queue.new

Thread.new { ping(pings, "passed message") }
Thread.new { pong(pings, pongs) }

puts pongs.pop

When using queues as method parameters in Ruby, we don’t have the same level of compile-time type safety as in some other languages. However, we can still design our methods to clearly indicate their intended use (send-only or receive-only) through naming conventions and documentation.

In this example:

  1. We define a ping method that only sends a message to a queue.
  2. We define a pong method that receives a message from one queue and sends it to another.
  3. In the main execution, we create two queues, pings and pongs.
  4. We use Thread.new to create new threads for our ping and pong operations, simulating concurrent execution.
  5. Finally, we print the message received from the pongs queue.

To run the program:

$ ruby channel_directions.rb
passed message

This example demonstrates how to use Ruby’s Thread and Queue classes to achieve behavior similar to channel directions in other languages. While Ruby doesn’t have built-in concepts like send-only or receive-only channels, we can still design our code to respect these patterns.