Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Regex unapply in for comprehension with if guard not compiling

Tags:

scala

Why is that the following will not compile

for {
    s <- List.empty[String]
    regex <- List.empty[scala.util.matching.Regex]
    regex(ss) = s
    if ss == "foo"
} yield s

But removing the if

for {
    s <- List.empty[String]
    regex <- List.empty[scala.util.matching.Regex]
    regex(ss) = s
} yield s

or rearranging the order of the two lists in the for comprehension

for {
    regex <- List.empty[scala.util.matching.Regex]
    s <- List.empty[String]
    regex(ss) = s
    if ss == "foo"
} yield s

compiles?

Scalafiddle: http://scalafiddle.net/console/2519ff98d434cb522589f54a9c5fcf55

like image 219
Klugscheißer Avatar asked Jul 26 '17 17:07

Klugscheißer


1 Answers

You can see the translated for-comprehension using this command:

scalac -Xprint:all <file>.scala

In your first example the resulting code looks like this (I cleaned up the output a bit):

List.empty[String]
  .flatMap(((s) =>
    List.empty[scala.util.matching.Regex]
      .map(regex => {
        private[this] val x$2 =
        s match {
          case (x$1@regex((ss@_))) => scala.Tuple2(x$1, ss)
        };
        val x$1 = x$2._1;
        val ss = x$2._2;
        scala.Tuple2(regex, x$1)
      }).withFilter((x$3 => x$3 match {
      case scala.Tuple2((regex@_), regex((ss@_))) => ss.$eq$eq("foo")
    })).map(((x$4) => x$4 match {
      case scala.Tuple2((regex@_), regex((ss@_))) => s
    })))
  )

The problem seems to be that the withFilter clause uses the expression regex(ss) directly in the case statement, but the value regex it is not defined there. I'm not sure if this can be considered a flaw in the language specification, or in the compiler. The error message is certainly not very helpful.

You can read up on the details in chapter 6.19 of the Scala language specification.

like image 119
devkat Avatar answered Nov 11 '22 01:11

devkat