Wednesday, January 28, 2009

Scala is static- is Scala dynamic?

Despite being statically typed, Scala is not an inflexible language. Smarter folks than me have commented on extending the behavior of classes dynamically using implicits.

I want to focus on another feature of Scala which allows for dynamic behavior. In concurrent programming with actors, the default handling involves pattern matching on the messages received. Pattern matching and actor concurrency have been borrowed from Erlang- a dynamic language by nature- and have been one of the key differentiating concepts compared to languages I've learned before.

When calling a method on a class, you have to know the method signature at compile-time. The types of the parameters you pass must be defined (even through an implicit type conversion). But when you pass a message to an actor (something of an asynchronous method call), you don't need to care what type of class the actor is or what type of messages it can process- at least at compile time:

import scala.actors._
import scala.actors.Actor._

val a = actor {
loop {
react {
case i: Int => println("Got an integer")
case o: AnyRef => println(o.getClass)
}
}
}

a ! 2
a ! 2.8
a ! "what is this?"


There's an unassuming case denoted by the underscore character (_). This is the so-called catch-all case, the moral equivalent of Ruby's method_missing. As you can see, you can send any object to the actor, and all undefined classes can be handled dynamically by this placeholder case.

Of course, the spirit of Scala doesn't encourage handling patterns using the catch-all method. You can send messages to actors only through a typed scala.actors.Channel:

import scala.actors._
import scala.actors.Actor._

val c = new Channel[Int](actor {
loop {
react {
case _ ! _ => println("test")
}
}
})

c ! 2



Once you use this Int-typed Channel, you can only send Int messages to it (unless there are any implicit conversions). For instance this would be caught by the compiler and fail with an error message:


c ! "2"
:10: error: type mismatch;
found : java.lang.String("2")
required: Int
c ! "2"
^


The Channel is constructed using an actor as an argument. This actor can then match by the scala.actors.! class (yes, it's the name of the class) and check which messages have arrived through which channels.

This took awhile to discover, since the best documentation is in the source itself. If there are any other (and better) idioms for using scala.actors.Channel, I'd be happy to learn them!

No comments: