When two branches are not enough
An if with an else splits the program into two paths. Often there are more than two cases: a grade can be failing, passing, good or perfect. Adding else if branches lets one chain handle as many outcomes as you need.
val language = "Python"
if (language == "Scala") {
println("It's super popular!")
} else if (language == "Python") {
println("It's so simple!")
} else if (language == "Java") {
println("It's pretty hardcore!")
} else {
println("It's exotic!")
}
The chain is checked from the top. language == "Scala" is false, so the program moves on. language == "Python" is true, so it runs that block and prints It's so simple!. The remaining conditions are never evaluated. If none of the conditions is true, the final else runs. With language set to "Go" the output would be It's exotic!.
Rules of the chain
- Exactly one block runs when the chain ends with an
else. At most one runs when it does not. - Order matters. The first condition that is true wins, and everything below it is skipped.
- Each later condition can rely on the earlier ones being false. That is why you can write fewer comparisons, as the exercise shows below.
- The final
elseis optional and has no condition. It catches every case the branches above did not.
Order mistakes
Because the first match wins, broad conditions placed too early hide the narrow ones. Take this version of a grade check:
def wrong(grade: Int): String =
if (grade <= 9) "Good Job"
else if (grade <= 7) "Passed the test"
else "Perfect"
println(wrong(6))
Good Job
A grade of 6 is also at most 9, so the first branch catches it and the second can never run. Put the most restrictive condition first, as in the lesson's chain, which starts from the lowest grades and moves up.
Chains are expressions
In Scala, if and else produce a value, so a chain can be returned from a method or bound to a val instead of printing in each branch:
def label(grade: Int): String =
if (grade < 5) "Failed the test"
else if (grade <= 7) "Passed the test"
else if (grade <= 9) "Good Job"
else "Perfect"
Here the final else is what guarantees a String in every case. An if without else produces the empty value () of type Unit when its condition is false, so it cannot stand in for a String. The lesson's exercise only prints, so it uses blocks with println.
The lesson's exercise
The code starts with val grade = 8. The task has three steps.
- Start the chain with an
if. It prints"Failed the test"whengrade < 5. Failing grades are handled before anything else. - Add two
else ifbranches. The first prints"Passed the test"whengrade <= 7. The second prints"Good Job"whengrade <= 9. "Up to 7" includes 7, so the comparisons use<=. The first branch to match wins. A grade that reaches the firstelse ifis already known to be at least 5, so there is no need to writegrade >= 5 && grade <= 7. - Finish with an
else. It prints"Perfect"for every grade above 9.
val grade = 8
if (grade < 5) {
println("Failed the test")
} else if (grade <= 7) {
println("Passed the test")
} else if (grade <= 9) {
println("Good Job")
} else {
println("Perfect")
}
With grade = 8, the first test (8 < 5) and the second (8 <= 7) are false, and the third (8 <= 9) is true, so the program prints Good Job. The boundaries behave like this:
| grade | output |
|---|---|
| 3 | Failed the test |
| 5 | Passed the test |
| 7 | Passed the test |
| 9 | Good Job |
| 10 | Perfect |
Common mistakes
- Writing
elseiforelif. Scala spells it as two words:else if. - Using separate
ifstatements. Independentifs all run their checks, so a grade of 8 could print more than one message. Chain them withelse ifwhen the cases exclude each other. - Off-by-one boundaries. Writing
grade < 7instead ofgrade <= 7would send a 7 to the"Good Job"branch.
Key takeaways
- An
if/else if/elsechain picks the first branch whose condition is true. - Later branches only run when every earlier condition was false.
- Put narrower conditions before broader ones, and finish with an
elsefor everything else. - A chain is an expression in Scala, so it can produce a value.
