In Scala 3, how to replace General Type Projection that has been dropped?

421 Views Asked by At

This code does not compile in Scala 3 since type projection on an abstract type is now invalid:

trait Entity:
  type Key

type Dictionary[T <: Entity] = Map[T#Key, T]

The compiler complains that T is abstract and type projection is therefore no more available:

T is not a legal path
since it is not a concrete type

How could you define the above Dictionary type in Scala 3?

1

There are 1 best solutions below

0
Dmytro Mitin On
trait Entity:
  type Key

object Entity:
  type Aux[K] = Entity { type Key = K }

// match type
type EntityKey[T <: Entity] = T match
  case Entity.Aux[k] => k // k being lower-case is significant

type Dictionary[T <: Entity] = Map[EntityKey[T], T]

I had to introduce Aux-type because match types seem not to work with refined types

type EntityKey[T <: Entity] = T match
  case Entity { type Key = k } => k // Not found: type k

Beware that on value level match types can work not so well as type projections: Scala 3: typed tuple zipping

  • Besides match types, also type classes can be an alternative to general type projections
trait Entity:
  type Key

// type class
trait EntityKey[T <: Entity]:
  type Out

object EntityKey:
  type Aux[T <: Entity, Out0] = EntityKey[T] { type Out = Out0 }

  given [K]: EntityKey.Aux[Entity { type Key = K }, K] = null

// replacing the type with a trait
trait Dictionary[T <: Entity](using val entityKey: EntityKey[T]):
  type Dict = Map[entityKey.Out, T]

What does Dotty offer to replace type projections?

https://users.scala-lang.org/t/converting-code-using-simple-type-projections-to-dotty/6516

Dotty cannot infer result type of generic Scala function taking type parameter trait with abstract type