Scala pattern matching variable binding

advertisements

Why can't I bind the variable in @-style when the extractor return Option[<Type>]? I.e. this one does not work:

object IsUpperCase {
  def unapply(s: String): Option[String] = {
    if (s.toUpperCase() == s) {
      Some(s)
    } else {
      None
    }
  }
}

val s = "[email protected]"
s match {
  case u @ IsUpperCase() => println("gotcha!") // what? "wrong number of arguments for object IsUpperCase"?
  case _ =>
}

But this one works!

val s = "[email protected]"
s match {
  case IsUpperCase(u) => println("gotcha!")
  case _ =>
}

From the other hand, if IsUpperCase looks like this:

object IsUpperCase {
  def unapply(s: String): Boolean = {
    return s.toUpperCase() == s
  }
}

Then the first example works, and the second does not! Why is it this way?


what? "wrong number of arguments for object IsUpperCase"?

case u @ IsUpperCase() => println("gotcha!")

Well, yes. The return type of unapply is Option[String], which means the pattern match of IsUpperCase must accept a parameter, like this:

case u @ IsUpperCase(_) => println("gotcha!") // I don't care about the parameter

The unapply definition that fits the first pattern is this:

object IsUpperCase {
  def unapply(s: String): Boolean = s.toUpperCase() == s
}

That can be used to pattern match against IsUpperCase().