Tag Archives: case

Matching a combination of class and trait in Scala

While doing some development with Scala I discovered that it is possible to match combinations of a class and traits. It might seem obvious if you already know it, but I didn’t.

What happened is that I needed something like matching that kind of combination… and this speaks to something about Scala that I love: it becomes intuitive after a while. So how did I find that such matching is possible? I simply tried… =)

This is what this feature looks like:

msg match {
  case x: X with Z => println("matching combination!")
}

In this case, X would be a class, and Z a trait. The case x will be triggered only if msg is an instance of class X and mixes in trait Z. With this, we make sure to have access to all members both from the class and from the trait, while being really type safe about the matching. No unsupported combinations will pass through, and no need for castings, like would be necessary in Java.

Lets try a dummy example. Imagine we have a Superman class, and two traits: BlueCape and RedCape, like the following code:

class Superman(val realname: String)
trait BlueCape
trait RedCape

Now, we want to match on a Superman instance, but we want to know if it is fake or not. Finally, we also want to print the guy’s name, which means we need access to the realname field. This is how you could do that:

def whichSuperman(superman: AnyRef) = superman match {
  case s: Superman with RedCape => println("real superman: " + s.realname)
  case f: Superman with BlueCape => println("fake superman: " + f.realname)
}

Flexible and type safe! And if the traits had any field, we would be able to access them as well. Quick sample test code:

val mys = new Superman("clark") with RedCape
val myf = new Superman("clurk") with BlueCape

whichSuperman(mys)
whichSuperman(myf)

The part that matches the class is not very useful in this example, since this could be defined in the function parameter, but it was in my local scenario, where we are using actors and the messages can be AnyRef.

If you want to know a bit more about pattern matching, I wrote about it a while ago here. I also described how to match a range of numbers here.


Scala Pattern Matching: the reason to fall in love with Scala

Scala has a lot of interesting features and, among them, one of the most interesting ones is Pattern Matching. If you still need a reason to try Scala this is the one. Actually, I might be exaggerating a little bit, but this feature is really interesting. Really. ;)

In summary, Pattern Matching looks like switch statements in Java. But there are a couple of things to keep in mind:

  • Using switch statements in Java is usually a code smell, i.e., something to avoid, risking your good OO design. This is not the case in Scala, where pattern matching is a core feature of the language, and should be leveraged by your applications.
  • Unlike in Java, there is basically no limits in terms of what you can use in the case clause. This, combined with the fact that Scala is a functional language, letting you pass functions around, gives you insane flexibility.

Lets go through a (very) simple example so that you can see by yourself at least part of this power. Suppose you are writing a function that takes an object of any type, and prints some information about it. Here is how you could do this:

class PrettyPrinter {
  def print(obj: Any) = {
    obj match {
      case 1 => println("number one")
      case Client("john") => println("special client: john")
      case Client(name) => println("client: " + name)
      case other => println(other)
    }
  }
}
case class Client(name: String)

object PatternMatchingTest {
  def main(args: Array[String]): Unit = {
    var printer = new PrettyPrinter
    printer.print(1)
    printer.print(new Client("jcranky"))
    printer.print(new Client("john"))
    printer.print("RandomStuff")
  }
}

Notice that, in the same clause, we are matching:

  • an integer number;
  • a specific Client
  • any other Client
  • any object of any class

Very flexible. For instance, in the case where we match any client, notice also that we capture the client’s name “automagically”, and use it in the println call.

That’s all for now. What do you think? Is this powerful enough for you? =D

EDIT:

I forgot to mention the expected output of the code above… so here it is:


number one
client: jcranky
special client: john
RandomStuff


Follow

Get every new post delivered to your Inbox.