This article is based on Scala in Action , to be published on Fall 2011. It is being reproduced here by permission from Manning Publications. Manning publishes MEAP (Manning Early Access Program,) eBooks and pBooks. MEAPs are sold exclusively through Manning.com. All pBook purchases include free PDF, mobi and epub. When mobile formats become available all customers will be contacted and upgraded. Visit Manning.com for more information. [ Use promotional code ‘java40beat’ and get 40% discount on eBooks and pBooks ]
also read:
Methods and Pattern Matching
Introduction
Expression-oriented programming challenges some good practices from other languages. A common practice in Java programming is having a single point of return for any method. This means that, if there is some kind of conditional logic, the developer creates a variable that contains the eventual return value. As the method flows, this variable is updated with what the method returns. The very last line in every method is a return statement. See an example in listing 1.
Listing 1 Java Idiom: One return statement
def createErrorMessage(errorCode : Int) : String = { var result : String = _ #1 errorCode match { case 1 => result = “Network Failure” #2 case 2 => result = “I/O Failure” case _ => result = “Unknown Error” } return result; } #1 Initializes to default #2 Directly assigns result
As you can see, the result variable is used to store the final result. The code falls through a pattern match, assigning error strings as appropriate and then returns the result variable. We can improve this code slightly using the expression-oriented syntax that pattern matching allows. A pattern match actually returns a value. The type of the value is determined as a common super type from all case statement returns. Pattern matching also throws an exception if no pattern is matched, so we’re guaranteed a return or error here. Let’s translate the code for an expression-oriented pattern match (listing 2).
Listing 2 Updated createErrorMessage with expression-oriented pattern match
def createErrorMessage(errorCode : Int) : String = { val result = errorCode match { #1 case 1 => “Network Failure” #2 case 2 => “I/O Failure” #2 case 3 => “Unkonwn Error” #2 } return result } #1 Assigning pattern match #2 Returns expression
You’ll notice two things. First, we changed the result variable to a val and let the type inferencer determine the type. This is because we no longer have to change the val after assignment, the pattern match should determine the unique value. So, not only have we reduced the size and complexity of the code, we’ve also increased immutability in the program. Immutability refers to the unchanging state of an object or variable. Immutability is the opposite of mutability. Mutability is the ability of an object or variable to change or mutate during its lifetime. You’ll frequently find that expression-oriented programming and immutable objects work very well together.
The second thing we’ve done is remove any kind of assignment from the case statements. The last expression in a case statement is the “result” of that case statement. We could have embedded further logic in each case statement if necessary, as long as we eventually had some kind of expression at the bottom. The compiler will also warn us if we accidentally return the wrong type.
The code is looking a lot more concise; however, we can still improve it somewhat. In Scala, most developers avoid return statements in their code, preferring to have the last expression be the return value (similar to all the other expression-oriented styles). In fact, for the createErrorMessage method, we can remove the intermediate result variable altogether. Let’s take a look at listing 3 for the final transformation.
Listing 3 Final expresison-oriented createErrorMessage method
def createErrorMessage(errorCode : Int) : String = errorCode match { case 1 => “Network Failure” case 2 => “I/O Failure” case _ => “Unknown Error” }
Notice how we haven’t even opened up a code block for the method? The pattern match is the only statement in the method, and it returns an expression of type String.
Summary
We’ve completely transformed the method into an expression-oriented syntax. Notice how much more concise and expressive the code is. Also note that the compiler will warn us of any type infractions or unreachable case statements.