In Scala 3, how to define unapply method to extract type argument in pattern matching?

212 Views Asked by At

So I found some esoteric code when upgrading an old Scala 2 library, the gist of it looks like this:

object MatchExtractTypeArg {

  import scala.reflect.runtime.universe.TypeTag

  def mapType(k: TypeTag[_], v: TypeTag[_]) = {

    (k, v) match {
      case (k: TypeTag[a], v: TypeTag[b]) =>
        implicit val kkk = k
        implicit val vvv = v
        implicitly[TypeTag[Map[a, b]]]
    }
  }

  def main(args: Array[String]): Unit = {

    val t1 = implicitly[TypeTag[Int]]
    val t2 = implicitly[TypeTag[String]]

    val r = mapType(t1, t2)
    println(r)
  }
}

the pattern matching case (k: TypeTag[List[a]], v: TypeTag[List[b]]) is fairly difficult to understand. after some investigation, I could only speculate that the following unapply function was used on k & v to determine type a & b:

    // (in scala.reflect.runtime.universe.TypeTag definition)
    def unapply[T](ttag: TypeTag[T]): Option[Type] = Some(ttag.tpe)

After Scala 3 upgrade, the above code should becomes:

object MatchExtractTypeArg {

  def mapType(k: Typeable[_], v: Typeable[_]) = {

    (k, v) match {
      case (k: Typeable[a], v: Typeable[b]) =>
        given kk: Typeable[a] = k
        given vv: Typeable[b] = v
        summon[Typeable[Map[a, b]]]
    }
  }

  def main(args: Array[String]): Unit = {

    val t1 = summon[Typeable[Int]]
    val t2 = summon[Typeable[String]]

    val r = mapType(t1, t2)
    println(r)
  }
}

It apparently compiles without a problem, but when trying to figure out its mechanism, I found that the unapply method being defined under Typeable has an entirely different signature, and can't extract any type argument.

Am I not upgrading code properly? How could it be possible that the new extractor still works in Scala 3?

0

There are 0 best solutions below