scala-logo-small

How Scala PartialFunction is a Practical and Elegant Solution

Why would I want just part of something?
Scala is sometimes criticized for being overly complicated which I don’t understand at all. Instead, I see some of the most elegant and most practical code constructs I have ever seen. One of these elegant and practical constructs is the PartialFunction. I think they are awesome.

The name might make you think of half of a function or something. That’s not it, actually. That’s more of the concept of function currying *. No, the concept of a partial function comes from math where there are total and partial functions. Total functions are functions that work on the total set of possible inputs. Partial functions are functions that work on only a partial set of possible inputs.

In Java, this might be similar to methods with guard clauses either weeding out bad inputs or enforcing contracts.

List<Integer> getStringLengths(List<String> listOfStrings) {
  if(listOfStrings == null || listOfStrings.isEmpty()) {
    return Collections.<Integer>emptyList();
  }
  //etc...
}

You may also have seen keywords like “require” or “assert” used in Java or Scala.

//RequireExample.scala
object RequireExample {
  def main(args: Array[String]) {
    def stringLengths(l: List[String]): List[Int] = {
      assert(l != null)
      assert(!l.isEmpty)
      l.map(_.length)
    }

    val hiHowAreYou = List("Hi,", "how", "are", "you")
    val badHiHowAreYou = List()

    val lenths = stringLengths(hiHowAreYou)
    //val lengths2 = stringLengths(badHiHowAreYou)
  }
}

PartialFunctions are often a better way to handle this kind of thing. They are more direct and therefore more clear.

I always learn best through example so lets make this practical right away.

String Length Example

What if you have a list of multiple types (a heterogenous list) and you need to get the lengths of all the strings. This specific action may not be something you envision yourself doing every day but the concept comes up often enough. It might be everything from finding users in a list who need to get a reminder email to finding all the products with organic vegetables in a list of grocery store products.

To keep our example simple and maintain focus on PartialFunction usage, we’ll just stick to going through a list of multiple types (a heterogenous list) and getting the lengths of all the strings.

By the way, at the end of the example I’ll show you how much code this would take in Java. I think you’ll appreciate how Scala cuts right to the chase on this.

Get to the code, already!
Alright, alright! Here’s the full code. Study that for a second and then we’ll walk through it.

Ah, that is so nice and to the point!

Here’s what is going on there, line-by-line.

Line 3: Here we just manually create a list full of random values (a List[Any]).

Line 5: On line 5 we create the stringLengths PartialFunction. The syntax of implementing a PartialFunction is easy. Just say “new PartialFunction” and pass the types. A PartialFunction always takes two types which represent the input type and the output type. It has this definition:

trait PartialFunction[-A, +B] extends (A) ⇒ B

For our example, we want to accept the Any type as the initial input, and we’re going to output a tuple which is a (String, Integer) so that we can return any strings we find in the list along with their length.

Line 6: A PartialFunction always implements two functions and apply is the first one. Apply is the workhorse of our PartialFunction, the function that actually takes the input and creates the output. In our case, we know we’ll have an Any input and we’ll need to cast it to a string and construct the tuple with that string and its length.

Line 7: isDefinedAt is the second function a PartialFunction always implements. This is the function that defines the partial set of inputs we are operating on here. In our case, we’re not operating on any Any, but only those that are not null and which are Strings.

Line 10: Now that we have a PartialFunction, we can do some fancy stuff with it! Like make use of some nice built-in language constructs such as the collect function built into sequences. Think of collect like a filter + a map, made possible by using a PartialFunction. Our PartialFunction will filter the list down to values matching isDefinedAt, then map them to an output using apply.

And that’s all there is to it!

Shorthand Partial Functions with the case keyword

An anonymous function with a case and no match is actually shorthand for a partial function. So this example is equivalent to the above:

Cue gasps, applause, and wonder!

If you already think about match statements as a way to enforce at compile-time that the total set of possible inputs was covered (“exhaustive pattern matching“) then this syntax will make sense to you. It is not exhaustive; it is partial.

PartialFunction is sometimes a better alternative to Option

In Scala Options for Dummies: Part 1 I gave almost this exact same example but used map and flatMap with Option in order to demonstrate how you could prevent NPE’s against data given a Scala program from Java. In that example, to achieve the above, we had to go through a series of steps to get the desired result:

listOfSomeStuffFromSomewhere.map(Option(_)).flatMap(x => x).map(_.length)

In that example, though, we knew we already had a list of string.

This shows how if you really aren’t worried about “None” data then don’t use Option. If all you want to do is focus on a partial set of data, then a PartialFunction is the better choice. The Option type is more useful though when you want to return the data elsewhere and make sure that the caller knows there was None for a particular case. Both have their uses.

That’s nice but we can easily do this in Java with if statements

Really? You’ve been programming in Java too long! I wouldn’t call it easy! Nothing in this example is easy in Java. It is just painstaking and verbose. Try implementing it. Or if you’re lazy, I already have. Check it out. I rather like the Scala version. Especially considering that this is a purposefully oversimplified and dumbed-down example! A real world example where operations are happening over complex objects would be awful.

Final words
I hope you found this exciting and are eager to use PartialFunction in your next code! See you next time…

Leave a Reply

Your email address will not be published. Required fields are marked *