I'm trying to migrate my mind from Java background (and a bit of Scala 2) to Scala 3 and to implement a kind of version of PartialFunction.orElse but with union type as an input parameter instead of intersection type:
trait F[A, B] extends (A => B) {
def orElse[A1, B1](other: F[A1, B1]): F[A | A1, B | B1] = {
val self = this
new F[A | A1, B | B1] {
override def apply(v: A | A1): B | B1 = {
helper(v)
}
transparent inline def helper(v: A | A1): Any = {
inline v match {
case _: A => self.apply(v.asInstanceOf[A])
case _: A1 => other.apply(v.asInstanceOf[A1])
}
}
}
}
}
But I ended up with a fact that both calls go to the first branch of "match":
val f1 = new F[Int, String] {
override def apply(v: Int): String = s"Int => String : $v"
}
val f2 = new F[String, Int] {
override def apply(v: String): Int = v.length
}
val f = f1.orElse(f2)
println(f(42)) // prints "Int => String : 42"
println(f("hello")) // fails in runtime because of trying casting String to Int
So, my question is, is it even possible? If yes, what am I missing?