Extracting with regular expressions

Reading thru the Programming in Scala 4ed, in 26.7 “What’s more, every regular expression in Scala defines an extractor.”

and in the example:

val Decimal = """(-)?(\d+)(\.\d*)?""".r
val Decimal(sign, integer part, decimal part) = "-1.23"

my question is how does that unapply method get defined for each Decimal object? Thru some runtime magic?

Regex objects don’t have an unapply method. They use unapplySeq, which uses varargs and returns an Option[Seq[A]]. The documentation only mentions shortly in the last paragraph, that this alternative to unapply exists.

2 Likes

Thanks for the reply.

My confusing point is how does the compiler know the decimal need to match the 3 captures. Checked a little further and it turns out the compiler does NOT.

So the match is more like:

Decimal.findMatches("-1.23") @unchecked match {
  case (sign, integerpart, decimalpart) => (sign, integerpart, decimalpart)
}

and just throw runtime error: scala.MatchError when the match fails.

Yes, but this is generally true for any pattern assignment, as the exhaustiveness checks only work well for statically known parts.

case class Foo(i: Int)
def foo(x: Boolean): Any = if(x) Foo(1) else ""

val Foo(y) = foo(true) // y: Int = 1

val Foo(y) = foo(false) // scala.MatchError:  (of class java.lang.String)

So if you aren’t sure at compile time, that the pattern will match, a match expression with a branch for the non-matching case is better.

1 Like