jamborta jamborta - 1 year ago 95
Scala Question

Prove upper type bound for generic types

I have a type class which I'd like to use to store a type of an object:

trait RetainType {
type A
}

object RetainType {
def apply[A0](): RetainType = new RetainType{
type A = A0
}
}


Given the following class:

trait Annotation
class Entity extends Annotation


I would like the compiler to prove that
RetainType.A
extends
Annotation
:

def hasAnnotation[A <: Annotation] = Unit


But using
RetainType
the compiler does not seem to resolve this:

val retainType = RetainType[Entity]
hasAnnotation[RetainType.A] //throws an error: type arguments [retainType.A] do not conform to method hasAnnotation's type parameter bounds [A <: Annotation]


It works ok if the type is specified:

hasAnnotation[Entity] //works fine


Anyway the compiler can prove this relation?

Answer Source

You messed up the signature of RetainType.apply:

def apply[A0](): RetainType

The return type does not mention A0, so it is "forgotten". That is, in

val x = RetainType[Int]

x.A is completely abstract; the compiler cannot prove that x.A = Int because apply's signature erased that information. Use a refinement type:

object RetainType {
  def apply[A0](): RetainType { type A = A0 } = new RetainType { override type A = A0 }
}

You may want to use the Aux pattern to make this nicer to work with:

object RetainType {
  type Aux[A0] = RetainType { type A = A0 }
  def apply[A0](): RetainType.Aux[A0] = new RetainType { override type A = A0 }
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download