Does it make any sense to use pattern matching in Scala with really simple cases?
-
06-04-2021 - |
Question
In 'Programming in Scala, Second Edition' at page 410 you can find class Simulation which have the following method:
private def next() {
(agenda: @unchecked) match {
case item :: rest =>
agenda = rest
curtime = item.time
item.action()
}
}
I'm curious why Odersky implemented this with pattern matching rather than just like that:
private def next() {
val item = agenda.head
agenda = agenda.tail
curtime = item.time
item.action()
}
Is pattern matching so efficient that it doesn't matter at all? Or it was just not so perfect example?
Solution
Normally I'd write it the way you did. (Even though pattern matching is quite efficient, it is not as efficient as head/tail.) You'd use pattern matching if
- You wanted to practice pattern matching
- You wanted a
MatchException
instead of aNoSuchElementException
- You were going to fill in other cases later.
OTHER TIPS
There are a couple reasons:
Part of the point of the book is to get you thinking in Scala (functional) terms; pattern matching is the functional-programming equivalent.
Pattern matching and the functional approach are the natural pattern in Scala, and allow things like concurrency in a natural way; learn that pattern and your Scala programs will be ready for more advanced uses.
Pattern matching is more idiomatic in Scala, and more easily protects you from boundary conditions.
In the code
private def next() {
val item = agenda.head
agenda = agenda.tail
curtime = item.time
item.action()
}
Both agenda.head
and agenda.tail
will throw a NoSuchElementException
exception if agenda
is an empty list, so to make it actually work you need to add a check for that.
The pattern matching version actually has a similar issue (as noted in th comments), but I find the fix cleaner, as all you have to do is add another pattern:
private def next() {
(agenda: @unchecked) match {
case item :: rest =>
agenda = rest
curtime = item.time
item.action()
case _ => {}
}
}
My guess is first that exceptions are not a worry here, there is probably some check before this "next" method is called. In fact, this is probably the reason for the "unchecked" annotation too, so he can really not have to put an extra case _ =>
. I think the reasoning was more that he wanted to use "unapply". An alternative here without the pattern matching, but also without head
and tail
could be something like:
private def next() {
val item :: rest = agenda
agenda = rest
curtime = item.time
item.action()
}