Rewriting Java in Scala & Making Code Lovely 6 – Pattern Matching

Pattern Matching – The Problem

I’m going to start off with a code snippet:

if (x instanceof SomeObject) {
  ((SomeObject)x).someMethod();
} else if (x instanceof SomeOtherObject) {
  ((SomeOtherObject)x).someOtherMethod();
}

Eugh. This is ugly. Not only that, it’s something we all see quite often when writing Java. No matter how well we’ve designed our APIs to avoid needing this sort of thing, it always creeps in somewhere.

Scala gives us a (huge) feature called Pattern Matching that allows us to tidy this up:

x match {
  case y : SomeObject => y.someMethod()
  case y : SomeOtherObject => y.someOtherMethod()
}

This is very similar to Java’s switch. The first case clause can be thought of as “if x is of type SomeObject then create a new variable, y, and set it to x”. Unlike some languages, Scala does not have fall through, if the first clause is matched then no other clauses are checked.

I prefer this to Java’s style of doing things because the cast/instance checking is done only once in your code. This is much more readable. Readability is only the tip of the iceberg. Pattern matching is very powerful and I’m now going to cover a few more uses of pattern matching.

Matching Constants

We can match against constants:

x match {
  case 1 => println("ONE!")
  case 2 => println("Two...")
  case _ => println("I can't count higher :(")
}

The first two cases here should be simple to follow. The third one is the same as Java’s default when using switch.

We can also return values out of a pattern match:

y = x match {
  case "one" => 1
  case "two" => 2
  case _ => 3
}

Oh, we can match against strings too… or, if we really want, we can match both in the same match:

x match {
  case 1 => 1
  case "one" => 1
  case _ => 2
}

Matching Regular Expressions

Scala also allows us to match against regular expressions.

val timeformat = """(\d\d):(\d\d)""".r
val time = "19:21"
time match {
  case timeformat(h, m) => println("It is " + m + " minutes past hour " + h)
  case _ => println("You gave me junk :(")
}

Read that again.

In the above example, we create a regular expression that matches times that look like “15:49″, i.e. the standard western way of doing 24 hour times. We then pattern match on the string “19:21″. The first clause will:

  • Check if the given string matches the regular expression
  • If a match is found, the two groups in the regular expression are substituted into variables h and m respectively

You can also ignore parts of the match using placeholder syntax (the underscore) if you want:

val timeformat = """(\d\d):(\d\d)""".r
val time = "4:21"
time match {
  case timeformat(h, _) => println("It is " + h + " o'clock")
  case _ => println("You gave me junk :(")
}

Short and readable. Nice.

Matching Types

Matching types can make equals method remarkably tidy. Suppose we’re writing the equals method for ThisClass which has a single field called someField:

def equals(other : Any) =
  other match {
    case other : ThisClass => other.someField == this.someField
    case _ => false
  }

Easy. The first clause says that if other is of type ThisClass then cast it to ThisClass and put it in a new variable called other (we can re-use the same name here without a conflict). We can then use other to compare the fields. The second clause is the result if no match was found in the first clause (i.e. if other is not an instance of ThisClass).

Matching Anything

In Scala you can use something called an extractor object to match against anything you could ever want. I’m not going to go into this in this post as it’s a big topic that deserves its own posting.

Summary

Many people compare pattern matching to “switch on steroids” or similar. This isn’t an exaggeration. It’s an extremely powerful tool and can lead to very succinct code (especially when doing things with regular expressions).

Rewriting Java in Scala & Making Code Lovely 5 – Structural Typing

What is structural typing?

Structural typing is a way of saying that we don’t care about the type of a variable but we do care about the structure of the type of a variable.

Here’s a simple example to explain this further:

def printArea(shape : { def area : Double}) {
    println(shape + " has area " + shape.area)
}

The interesting part of the above function is the type of the argument shape; shape is a structurally typed variable. We can pass any object we want to the printArea function so long as it has a function called area that returns a Double:

case class square(val sideLength : Double) {
  def area = sideLength * sideLength
}
 
printArea(square(5.0))
// square(5.0) has area 25.0
 
case class circle(val radius : Double) {
  def area = scala.math.Pi * radius * radius
}
 
printArea(circle(10.0))
// circle(10.0) has area 314.1592653589793

We can go as far as you want with specifying structural types:

def pointlessFunction(thing : { 
    def areaWithMultiplier(multiplier : Double) : Double
    def length : Double}) = {
  // ...
}

The above function takes any type that has two functions:

  • areaWithMultiplier that has one argument of type Double and returns a Double
  • length that returns a double

But, the above example is ugly. Type aliases to the rescue:

type t = {
  def areaWithMultiplier(multiplier : Double) : Double
  def length : Double
}
def pointlessFunction(thing : t) = {
  // ...
}

Here we’ve created a type alias t that aliases the complex structural type. We then use that type in the definition of pointlessFunction in the same way we’d use any other type.

What’s the use?

Very Reusable Functions

One of the great uses of structural types is that they allow us to create very reusable functions. For example, we could write a function that sorts a list of shapes according to their size without requiring that the shapes implement a common interface:

type hasArea = { def area : Double }
 
def sortShapes(list : List[hasArea]) : List[hasArea] = {
  list.sortWith(_.area < _.area)
}
 
sortShapes(
  List[hasArea](square(5.0), square(6.0), circle(2.0), circle(3.0))
)
// Result is: List(circle(2.0), square(5.0), circle(3.0), square(6.0))

We could then pass anything we wanted to this function: shapes, countries, building plans, anything with an area function.

This becomes incredibly useful when implementing algorithms. For example, an algorithm that determines how to fit different shapes into a box could be used on any type that implemented the required method.

Legacy Classes

Structural types are also a great way to make legacy types easier to use.

We are given two classes that represent different types of customers: BusinessCustomer, IndividualCustomer. Both of these classes have a method getPhoneNumber. They don’t share a base class. We want to use a library that allows us to call these people from our computer. The typical Java approach might be something like:

public void dial(Object customer) {
  String phoneNumber;  
  if (customer instanceof BusinessCustomer) {
    phoneNumber = ((BusinessCustomer)customer).getPhoneNumber();
  } else if (customer instanceof IndividualCustomer) {
    phoneNumber = ((IndividualCustomer)customer).getPhoneNumber();
  } else {
    throw IllegalArgumentException("Argument isn't a customter " + customer);
  }
  Dialer.dial(phoneNumber);
}

Ugh.

Apart from this being a lot of code for something simple, you won’t be told of errors at compilation time!

Enter structural typing:

def dial(customer : { def getPhoneNumber : String }) = {
  Dialer.dial(customer.getPhoneNumber)
}

Much better. Compile-time safe and far easier to follow.

Duck-Typing

Structural typing is effectively duck typing. Forget littering all your classes with random interfaces IsCloneable, IsSortable, IsComparable, IsJedi… use structural typing and we can say “so long as this argument has a certain property then I’ll use it”.

This gives us some of the benefits of dynamic typing (being able to use whatever we want wherever we want) without losing the benefits of a compiler to make sure we’ve not done something silly.

Under the Covers

Under the covers Scala generates byte-code similar to the following Java:

public void printArea(Object shape) {
    double area = (Double)shape.getClass().getMethod("area").invoke(shape);
    System.out.println("Shape " + shape + " has area " + area);
}

That’s reflection at work. The up-side of this is that we can use our functions from Java code – but without any compile-time type safety. All structural types get compiled down to Object and Scala does the work at run-time to determine if the argument fits the function.

Summary

Structural typing allows us to use arguments according to what properties they have, not what type they are. This can be a very powerful tool and lead to very neat code. It also gives us the benefit of greater compile-time checking when compared against using instanceof in lots of places.

If you want to see a great real-world example of structural typing then take a look at Java to Scala – Smaller Inheritance hierarchies with Structural Typing.