0

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.
user3103957
  • 636
  • 4
  • 16

2 Answers2

1

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))
Tim
  • 26,753
  • 2
  • 16
  • 29
  • Thanks for the reply Tim. Can you please let me know why my understanding is incorrect? What is understand is: 'ins' will be decomposed using unapply method and the returned values would be captured in x and y respectively. – user3103957 Mar 26 '22 at 10:02
  • You may use `Some` instead of `Option` to tell the compiler the match is exhaustive. – Luis Miguel Mejía Suárez Mar 26 '22 at 15:51
0

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) = "user3103957@stackoverflow.example.xyz"

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

val _tmpTuple2 =
  "user3103957@stackoverflow.example.xyz" 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.

Levi Ramsey
  • 18,884
  • 1
  • 16
  • 30