Scala/Expressions, Not Statements

Simple Conditional Branching edit

Frequently, we need to make a simple decision regarding which value a variable should instantiate to. Take for example a somewhat artificial case:

var result = ""
if(marks >= 50)
  result = "passed"
else
  result = "failed"
println("Your results just came in, you " + result + ".")

At first sight it does not seem so bad. But we can do better if the branching itself evaluates a value.

println("Your results just came in, you " +
  (if(marks >= 50) "passed" else "failed") + ".")

In fact, Java/C# provides you with the (...) ? (...) : (...) syntax just because it's very handy at times.

Often this construct saves the Scala programmer from inventing a silly name for a short-lived variable. Perhaps it's equally important that it does not assign a silly value to it to start with.

Of course, if the value is needed more than once you probably should introduce a value. Even then,

val result: String = if(marks >= 50) "passed" else "failed"
println("Your results just came in, you " + result + ".")
println("Your academic record now shows that you have " + result + " the course.")

This does not prevent you from using if ... else ... as statements. Statements, after all, are expressions.

Scaling It Up edit

Understandably if ... else if ... else ... chains are just as common, and they work just as fine in Scala. We might, for a finer result, try,

val result: String = 
  if(marks >= 85) 
    "A"
  else if(marks >= 70) 
    "B"
  else if(marks >= 60) 
    "C"
  else if(marks >= 50) 
    "D"
  else
    "F"
println("You've got " + result + ".")

But more than often we need to branch on values rather than conditions. Basically that's why we have switch in Java/C#. Scala uses match for this,

val result: String = 
  if(marks >= 85) 
    "A"
  else if(marks >= 70) 
    "B"
  else if(marks >= 60) 
    "C"
  else if(marks >= 50) 
    "D"
  else
    "F"
println("You've got " + result + ".")

result match {
  case "A" | "B" => println("Congratulations!")
  case "C" => println("There is room for improvement, though.")
  case _ => println("We are concerned about your progress.")
}

Several things look different. For one, these cases do not use break to indicate the end of a branch. You don't have a fall through. Not that you need to fall through. They make programs harder to read and reason about. You can, however, group equivalent cases so that the principal use of falling through switch statements can be handled. Although Scala does not have the default keyword, the underscore reads "anything else", so to speak.

If you, for some reason, try this in Java 1.6 or lower, you'll probably notice another difference. switch only handles primitive types (and String since Java 1.7) so a straightforward translation will have to use if chains with a couple of equals calls. Scala uses equals to match cases for objects to make the code cleaner to read.

We will have to say more on match here and there in this book. For now, you probably will appreciate the ability to mix conditionals and cases to handle very special cases, like,

case "D" if marks < 52 => println("Close call!")

Although to make sense, this case should sit above the default case.

Trying And Failing edit

Even a try ... catch ... block is an expression in Scala and this can result in remarkably readable code:

val n: Int = try {
  userInput.toInt
} catch {
  case _ => 0
}

As an aside, note that catch looks very much like match (and the underscore here means we don't care which specific exception was thrown).