qed
qed

Reputation: 23114

Extractor conflicts in scala

Code:

  case class Division(val number: Int) {
//    def unapply(divider: Int): Option[(Int, Int)] = if (number % divider == 0) Some(number/divider, 0) else None
//    def unapply(divider: Double): Boolean = number % divider.toInt == 0
    def unapplySeq(x: Float): Option[Seq[Int]] = {
      val seq = (3 to 10).map(i => i * x.toInt)
      println(seq)
      Some(seq)
    }
  }



  val divisionOf15 = Division(15)

//  val y = 5 match {
//    case divisionOf15(z, w) => println(s"$z, $w")
//    case _ => println(s"Not divisible")
//  }

//  val z = 5.0 match {
//    case divisionOf15() => println("Divisible")
//    case _ => println("Not divisible")
//  }

  val u = 5.0F match {
    case divisionOf15(f1, f2, _*) => println(s"$f1, $f2")
  }

If I uncomment these lines:

//    def unapply(divider: Int): Option[(Int, Int)] = if (number % divider == 0) Some(number/divider, 0) else None
//    def unapply(divider: Double): Boolean = number % divider.toInt == 0

An error crops up during compilation:

 Star pattern must correspond with varargs or unapplySeq
    case divisionOf15(f1, f2, _*) => println(s"$f1, $f2")
         ^

If I uncomment this line:

//    def unapply(divider: Int): Option[(Int, Int)] = if (number % divider == 0) Some(number/divider, 0) else None

I get two errors:

 scrutinee is incompatible with pattern type;
 found   : Int
 required: Float
    case divisionOf15(f1, f2, _*) => println(s"$f1, $f2")
                     ^
 Star pattern must correspond with varargs or unapplySeq
    case divisionOf15(f1, f2, _*) => println(s"$f1, $f2")
         ^

Am I doing something wrong or is this a bug? These extractors seem innocent and shouldn't conflict with each other.

Upvotes: 4

Views: 133

Answers (1)

0__
0__

Reputation: 67290

The language specification does not say anything about the concurrent presence of unapply and unapplySeq. It hints at their mutual exclusiveness, though:

an object which has a member method named unapply or unapplySeq

...

if the extractor object x does not have an unapply method, but it does define an unapplySeq method

This blog also states:

Note: if both unapply and unapplySeq are defined only unapply is used.

So either define different extractors (it doesn't seem obvious to me to overload the definitions in your case!), or go with unapply:

case class Division(val number: Int) {
  def unapply(divider: Int): Option[(Int, Int)] = 
    if (number % divider == 0) Some(number/divider, 0) else None
  
  def unapply(divider: Double): Boolean = number % divider.toInt == 0
  
  def unapply(x: Float): Option[Seq[Int]] = {
    val seq = (3 to 10).map(i => i * x.toInt)
    println(seq)
    Some(seq)
  }
}

val u = 5.0F match {
  case divisionOf15(Seq(f1, f2, _*)) => println(s"$f1, $f2")
}

Upvotes: 5

Related Questions