Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent this kind of bug - pattern matching and Nil

Tags:

scala

When you pattern match again Lists, you can use Nil to check for empty list. However, if the underlying type is an Iterable, you can still check for Nil, and it will break for empty Sets, etc... See following REPL session:

scala> val l: Iterable[Int] = List()
l: Iterable[Int] = List()

scala> l match {
     | case Nil => 1
     | case _ => 2
     | }
res0: Int = 1

scala> val l: Iterable[Int] = Set() 
l: Iterable[Int] = Set()

scala> l match {
     | case Nil => 1
     | case _ => 2
     | }
res2: Int = 2

Question is - how can I prevent this kind of issue? Obviously, if l is a type List, it's no bug. And if l is of type Set, it won't compile. But what if we have a class that has a list, define a function that pattern matches in this way, and then someone changes the class to take a generic iterable instead? Is this Nil vs. _ pattern match a bad idea in general?

like image 870
3 revs Avatar asked Feb 19 '12 09:02

3 revs


2 Answers

One possibility is to use a guard:

scala> val xs: Iterable[Int] = Set()
xs: Iterable[Int] = Set()

scala> xs match { case xs if xs.isEmpty => 1 case _ => 2 }
res0: Int = 1

Another way to do this is to use an if-else-expression (works best if you only have one or two conditions to check):

scala> if (xs.isEmpty) 1 else 2
res1: Int = 1
like image 72
kiritsuku Avatar answered Sep 26 '22 20:09

kiritsuku


Convert the scrutinee to a list to eliminate doubt.

l.toList match {
  case Nil => 1
  case xs  => 2
}
like image 43
retronym Avatar answered Sep 25 '22 20:09

retronym