I am trying to use a Scala3 type match to achieve something similar to type projections on abstract types in Scala2.
A minimal example is:
sealed trait Context
trait AContext extends Context
trait BContext extends Context
trait Data[C <: Context]
case class AData(name: String) extends Data[AContext]
case class BData(age: Int) extends Data[BContext]
type Input[C <: Context] = C match {
case AContext => AData
case BContext => BData
}
trait Doer[C <: Context]:
def doThing(data: Input[C]): Unit
class ADoer extends Doer[AContext]:
override def doThing(data: AData): Unit = println(data.name)
class BDoer extends Doer[BContext]:
override def doThing(data: BData): Unit = println(s"age: ${data.age}")
ADoer().doThing(AData("steve"))
BDoer().doThing(BData(40))
For some reason, the order of the statements in the type match clause are important. In this case ADoer passes the compiler and BDoer fails, stating the doThing method does not match the type signature. If the type match clauses puts case B first, then BDoer succeeds and ADoer fails.
Well, it's not surprising that the order of patterns in pattern matching is important. So it is in match types.
Match types work well on type level. On value level there many limitations
Scala 3: typed tuple zipping
Type-level filtering tuple in Scala 3
How to get match type to work correctly in Scala 3
Scala 3. Implementing Dependent Function Type
How do you deal with tuples of higher-order types?
How to prove that `Tuple.Map[H *: T, F] =:= (F[H] *: Tuple.Map[T, F])` in Scala 3
Tuples in Scala 3 Compiler Operations for Typeclass Derivation
scala 3 map tuple to futures of tuple types and back
Express function of arbitrary arity in vanilla Scala 3
Shapeless3 and annotations
In Scala 3, how to replace General Type Projection that has been dropped?
What does Dotty offer to replace type projections?
Sometimes match types are not so good as input types
but ok as output types
Sometimes type classes are better than match types
In your specific use case, you can make
AContext,BContextobjectsor classes
and your code will compile.
The thing is in reduction rules
https://docs.scala-lang.org/scala3/reference/new-types/match-types.html#match-type-reduction
When
AContext,BContextare just traits, then they are not disjoint and the compiler doesn't proceed to the next case.