Search code examples
scalaextractor

Scala pattern matching variable binding


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?


Solution

  • 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().