7

As a follow-up to this question

Here is some code that compiles and runs correctly, using captures.

val myString = "ACATCGTAGCTGCTAGCTG"

val nucCap = "([ACTG]+)".r

myString match {
   case nucCap(myNuc) => println("dna:"+myNuc)
   case _ => println("not dna")
}

>scala scalaTest.scala 
dna:ACATCGTAGCTGCTAGCTG

Here is simpler code, without capture, that does not compile.

val myString = "ACATCGTAGCTGCTAGCTG"

val nuc = "[ACGT]+".r

myString match {
     case nuc => println("dna")
     case _ => println("not dna")
}

>scala scalaTest.scala
scalaTest.scala:7: error: unreachable code

Seems like the matching should return a boolean regardless of whether a capture is used. What is going on here?

Community
  • 1
  • 1
Jeremy Leipzig
  • 1,914
  • 3
  • 21
  • 26

1 Answers1

8

In your match block, nuc is a pattern variable and does not refer to the nuc in the enclosing scope. This makes the default case unreachable because the simple pattern nuc will match anything.

An empty pair of parentheses on nuc will make the syntactic sugar work and call the unapplySeq method on the Regex:

myString match {
  case nuc() => println("dna")
  case _ => println("not dna")
}

One way to avoid this pitfall is to rename nuc to Nuc. Starting with an uppercase letter makes it a stable identifier, so that it refers to the Nuc in the enclosing scope, rather than being treated by the compiler as a pattern variable.

val Nuc = "[ACGT]+".r
myString match {
  case Nuc => println("dna")
  case _ => println("not dna")
}

The above will print "not dna", because here we are simply comparing Nuc to myString, and they are not equal. It's a bug, but maybe a less confusing one!

Adding the parentheses will have the desired effect in this case too:

myString match {
  case Nuc() => println("dna")
  case _ => println("not dna")
}
// prints "dna"

By the way, it is not a boolean that is being returned, but an Option[List[String]]:

scala> nuc.unapplySeq(myString)
res17: Option[List[String]] = Some(List())
scala> nucCap.unapplySeq(myString)
res18: Option[List[String]] = Some(List(ACATCGTAGCTGCTAGCTG))
Ben James
  • 121,135
  • 26
  • 193
  • 155