Operator Overloading in Scala

Scala supports operator overloading, which means that the meaning of operators (such as * and +) may be defined for arbitrary types.

Example: a complex number class:

class Complex(val real : Double, val imag : Double) {
  def +(other : Complex) = new Complex(
    real + other.real,
    imag + other.imag)

def (other : Complex) = new Complex( realother.real - imagother.imag, imagother.real + real*other.imag)

def magnitude() : Double = Math.sqrt(realreal + imagimag) }

Code that uses this class:

var C = new Complex(x, y)
var Z = new Complex(0.0, 0.0)

var count = 0

while (count < THRESHOLD && Z.magnitude() < 2.0) { Z = Z*Z + C count += 1 }

This code determines whether or not a complex number C is in the Mandelbrot Set.

Actors in Scala

Actor example code: actor.scala, actor2.scala

Actors are the main mechanism in Scala for expressing concurrency.

An actor is an object that waits to receive messages, which are arbitrary Scala objects/values. Each actor processes the messages it receives sequentially. (A queue called the mailbox is used to keep track of the messages sent to an actor.)

Because actors communicate by sending messages to each other, rather than modifying shared data structures, they are potentially a more robust and easy-to-use means for expressing concurrency and parallelism than threads.

Defining an actor class

An actor class should extend the Actor base class. Here is an example:

case object SayHello

class Hello(val name : String) extends Actor { def act() { loop { react { case SayHello => { println(name + " says hello") exit() } } } } }

A Hello actor will wait to receive a SayHello message. (SayHello is a case object, which is essentially a singleton object with no behavior.) When the message is received, it prints the message "name says hello" and then exits.

Sending a message

Messages are sent to actors using the ! operator, with the syntax

Here's a test program using the Hello actor class above:

object Main {
  def main(args : Array[String]) {
    val a = new Hello("Alice")
    a.start()

<span class="k">val</span> <span class="n">b</span> <span class="k">=</span> <span class="k">new</span> <span class="nc">Hello</span><span class="o">(</span><span class="s">"Bob"</span><span class="o">)</span>
<span class="n">b</span><span class="o">.</span><span class="n">start</span><span class="o">()</span>

<span class="n">a</span> <span class="o">!</span> <span class="nc">SayHello</span>
<span class="n">b</span> <span class="o">!</span> <span class="nc">SayHello</span>

} }

Note that actors must be started using the start() method before they start listening for messages.

If you run this program a few times, you will notice that the output does not appear in a predictable order. For example, on my computer:

This is because when a message sent,

Because actors process messages concurrently, they can be used for parallel computation, where parts of a computation are executed simultaneously on different processors/cores.

Waiting for a reply

Sometimes it is useful to be able to send a message to an actor and then wait for a reply. This is possible using the !! operator.

Example: here is an actor which accepts Add messages containing two integer values, computes the sum, and sends the sum back to the sender:

case class Add(val x : Int, val y : Int)

class Adder extends Actor { def act() { loop { react { case msg : Add => { val sum = msg.x + msg.y sender ! sum exit() } } } } }

Notice that when the sum is computed, it is immediately sent to sender, which is a function that identifies the sender of a received message.

Here is a main program which creates an Adder actor and uses it to add two integers:

object Main {
  def main(args : Array[String]) {
    val adder = new Adder
    adder.start()

<span class="k">val</span> <span class="n">f</span> <span class="k">=</span> <span class="n">adder</span> <span class="o">!!</span> <span class="k">new</span> <span class="nc">Add</span><span class="o">(</span><span class="mi">3</span><span class="o">,</span> <span class="mi">4</span><span class="o">)</span>
<span class="k">val</span> <span class="n">resultUntyped</span> <span class="k">=</span> <span class="n">f</span><span class="o">()</span>
<span class="n">resultUntyped</span> <span class="k">match</span> <span class="o">{</span>
  <span class="k">case</span> <span class="n">sum</span> <span class="k">:</span> <span class="kt">Int</span> <span class="o">=&gt;</span> <span class="o">{</span>
    <span class="n">println</span><span class="o">(</span><span class="s">"sum is "</span> <span class="o">+</span> <span class="n">sum</span><span class="o">)</span>
  <span class="o">}</span>
<span class="o">}</span>

} }

Here is a quick explanation of what is happening:

  1. The message new Add(3, 4) is sent to the actor using !!
  2. The result of the !! operator is a future: a function which, when called, will (eventually) produce a value
  3. The result of calling the future f() is an value whose type is Any, which is similar to Object in Java in the sense that it could represent any kind of value. This accounts for the fact that we can't predict what kind of reply message the actor will send.
  4. The match construct is used on the untyped result: matching it against the Int data type allows the result to be converted to an integer