Home > Net >  Syntactic sugar explanation of Scala'a unapply method
Syntactic sugar explanation of Scala'a unapply method

Time:03-27

I am getting an error in the extractor step (unapply method call). The error message is: Wrong number of arguments for the extractors. found 2; expected 0

Can someone please help what is causing the error (where my misunderstanding is).

class ABC(val name:String, val age:Int)  //class is defined.

object ABC{
    def apply(age:Int, name:String) = new ABC(name, age)  
    def unapply(x:ABC) = (x.name, x.age)                   
}


val ins = ABC(25, "Joe")  //here apply method is in action.
val ABC(x,y) = ins        //unapply is indirectly called. As per my understanding , 25 and Joe suppose to be captured in x and y respectively. But this steps gives error.

CodePudding user response:

The error I get is

an unapply result must have a member def isEmpty: Boolean

The easiest way to fix this is to make unapply return an Option:

def unapply(x: ABC) = Option((x.name, x.age))

CodePudding user response:

The unapply method in an extractor which binds values must return an Option. This is because there's no intrinsic guarantee that an extractor will always succeed. For instance consider this massively oversimplified example of an extractor for an email address:

object Email {
  def unapply(s: String): Option[(String, String)] =
    s.indexOf('@') match {
      case idx if idx >= 0 =>
        val (user, maybeSite) = s.splitAt(idx)

        if (maybeSite.length < 2 || maybeSite.lastIndexOf('@') > 0) None
        else Some(user -> maybeSite.tail)

      case _ => None
    }
}

At the application site:

val Email(u, s) = "[email protected]"

Turns into code that's basically (from the description in Programming In Scala (Odersky, Spoon, Venners (3rd ed))):

val _tmpTuple2 =
  "[email protected]" match {
    case str: String =>
      Email.unapply(str).getOrElse(throw ???)
    case _ => throw ???
  }
val u = _tmpTuple2._1
val s = _tmpTuple2._2

Technically, since the compiler already knows that the value is a String, the type check is elided, but I've included the type check for generality. The desugaring of extractors in a pattern match also need not throw except for the last extractor attempt.

  • Related