Search code examples
scalagenericsreflectionscala-reflecterasure

How to distinguish parameteric types?


I am confused about subtypes in Scala. My major question is how to distinguish C[T1] from C[T2]. There are two scenarios:

  1. C[T1] "equals" C[T2] because they are all subtypes of C.
  2. C[T1] does not "equal" C[T2] because C[T1] and C[T2] are different types eventually.

I have tried some ways like .getClass, seems that this strategy won't work because we have primitive types.

println(List[Int](1).getClass == List[Double](1.0).getClass) // True
println(List[Int](1).getClass.getCanonicalName) // scala.collection.immutable.$colon$colon
println(Array[Int](1).getClass == Array[Double](1.0).getClass) // False
println(Array[Int](1).getClass.getCanonicalName) // int[]

I now wonder is there some way I can do this?


Solution

  • List[Int] and List[Double] have the same class, but different types.

    import scala.reflect.runtime.universe._
    
    println(typeOf[List[Int]] =:= typeOf[List[Double]])//false
    println(typeOf[List[Int]].typeConstructor =:= typeOf[List[Double]].typeConstructor)//true
    println(typeOf[List[Int]])//List[Int]
    println(showRaw(typeOf[List[Int]]))//TypeRef(SingleType(SingleType(ThisType(<root>), scala), scala.package), TypeName("List"), List(TypeRef(ThisType(scala), scala.Int, List())))
    
    println(classOf[List[Int]] == classOf[List[Double]])//true
    println(classOf[List[Int]])//class scala.collection.immutable.List
    println(classOf[List[Int]].getCanonicalName)//scala.collection.immutable.List
    

    Array[Int] and Array[Double] have different both classes and types.

    println(typeOf[Array[Int]] =:= typeOf[Array[Double]])//false
    println(typeOf[Array[Int]].typeConstructor =:= typeOf[Array[Double]].typeConstructor)//true
    println(typeOf[Array[Int]])//Array[Int]
    println(showRaw(typeOf[Array[Int]]))//TypeRef(ThisType(scala), scala.Array, List(TypeRef(ThisType(scala), scala.Int, List())))
    
    println(classOf[Array[Int]] == classOf[Array[Double]])//false
    println(classOf[Array[Int]])//class [I
    println(classOf[Array[Int]].getCanonicalName)//int[]
    

    https://docs.scala-lang.org/overviews/reflection/overview.html

    https://typelevel.org/blog/2017/02/13/more-types-than-classes.html

    Type Erasure in Scala

    C[T1] "equals" C[T2] because they are all subtypes of C.

    They are not subtypes.

    https://www.scala-lang.org/files/archive/spec/2.13/03-types.html#conformance

    Subtype in Scala: what is "type X <: Y"?