Select in Scala

Scala’s select construct allows you to wait on multiple channel operations. Combining concurrent processes and channels with select is a powerful feature of Scala.

import scala.concurrent.{Future, ExecutionContext}
import scala.concurrent.duration._
import scala.util.{Success, Failure}

object SelectExample extends App {
  implicit val ec: ExecutionContext = ExecutionContext.global

  // For our example we'll select across two channels.
  val c1 = scala.concurrent.Promise[String]()
  val c2 = scala.concurrent.Promise[String]()

  // Each channel will receive a value after some amount
  // of time, to simulate e.g. blocking RPC operations
  // executing in concurrent processes.
  Future {
    Thread.sleep(1000)
    c1.success("one")
  }

  Future {
    Thread.sleep(2000)
    c2.success("two")
  }

  // We'll use `Future.firstCompletedOf` to await both of these values
  // simultaneously, printing each one as it arrives.
  for (i <- 1 to 2) {
    Future.firstCompletedOf(Seq(c1.future, c2.future)).onComplete {
      case Success(msg) => println(s"received $msg")
      case Failure(e) => println(s"Error: ${e.getMessage}")
    }
    Thread.sleep(1100) // Wait a bit before next iteration
  }

  // Wait for all futures to complete
  Thread.sleep(2100)
}

We receive the values “one” and then “two” as expected.

$ scala SelectExample.scala
received one
received two

Note that the total execution time is only ~2 seconds since both the 1 and 2 second sleep operations execute concurrently.

In this Scala version:

  1. We use Future and Promise to simulate channels and asynchronous operations.
  2. Instead of Go’s select, we use Future.firstCompletedOf to wait for the first completed future.
  3. We use onComplete to handle the result of each completed future.
  4. The Thread.sleep calls are used to simulate the timing of the original Go example.

This example demonstrates how to work with concurrent operations in Scala, although the exact semantics differ from Go’s channels and select statement.