Pattern Matching: Flow Control Made Beautiful

Posted by Matt Farmer on June 15, 2012 · 3 mins read

One of the things that really drew me to OpenStudy when I was considering it as the next step for my career was the use of Scala as the company’s weapon of choice. If you’re anything like me you never got any direct experience with Scala in your formal Computer Science education. In fact, the only reason that I had ever heard of Scala was because I had a professor at UGA, Dr. Miller, who was using it for his research.
After about eight months of working for OpenStudy, I still find things to be amazed at with Scala. One of the first examples of things that blew my mind was the Scala pattern matching. In most Scala pattern matching scenarios, what you’ll see is pattern matching on Scala case classes. These case classes are pretty clever concepts in and of themselves, but that’s an entirely different topic for a different day. Let’s take Scala’s Option type. Options can have one of two values: they can either be a None or a Some case class containing an instance of a specific type. So, I could, for example, have this variable:

val urlPath:Option[String]

This val could be a None, or could be a Some containing a String. So what if I want to change how my program behaves based on the value of this urlPath? Well, I could certainly do something like this, which leverages the isDefined attribute of Options:

if (urlPath.isDefined) { // Do something with the url via urlPath.get } else { // Do something else }

Sure, this works, but it isn’t very beautiful. It certainly isn’t very Scala-like. Indeed, what if you need to do different things with a url that is defined? So, let’s say we want to have different behavior based on whether or not the URL is Google or Bing.

if (urlPath.isDefined) { if (urlPath.get == “”) goToGoogle() else if (urlPath.get == “”) puke() }

You have the option of nesting if statements, as above, but it doesn’t look very pretty in any language. Also, as you add more conditions the levels of nesting will increase rapidly. So, let’s leverage some Scala patten matching. If we’re looking at the first example, we’d probably use something like this:

urlPath match { case Some(url) => // Do something with the url case _ => // Do something else because the url isn’t a some. }

The underscore is Scala’s wildcard character. It does a lot of different things. In this case, it’s the equivalent to the “default” statements in classic switch statements. It serves as a catchall so the compiler doesn’t complain to us about unhandled possibilities. We could have written it with a “None” in this case and have been as equally correct. So, then we come back to our second example. What if we want it to behave differently between Google and Bing?

urlPath match { case Some(url) if url == “” => goToGoogle() case Some(url) if url == “” => puke() case _ => // Default actions. }

Much prettier.