简体   繁体   中英

Scala reflection with TypeTags and singleton types

I've just started experimenting with the reflection API introduced in Scala 2.10 and would expect the code below to evaluate to true five times (REPL).

Unfortunately, only the first and last expressions really do. Can somebody explain why this is the case? It seems from the compiler's perspective all these type comparisons are ok or am I getting this wrong?

Is there a way to make this (at least one .type comparison) work?

import scala.reflect.runtime.universe._

class Test[A:TypeTag](val a:A) {
  val value:this.type=this
  def t1:TypeTag[Test[A]]=typeTag[Test[A]]
  def t2:TypeTag[this.type]=typeTag[this.type]
  def t3:TypeTag[_<:Test[A]]=typeTag[this.type]
}

val a:Test[String]=new Test("a")

a.t1.tpe<:<typeOf[Test[String]] //works as expected
a.t2.tpe<:<typeOf[Test[String]] //FAILS
a.t3.tpe<:<typeOf[Test[String]] //FAILS
a.t2.tpe<:<typeOf[a.type] //FAILS
typeOf[a.type]<:<typeOf[a.type] //this works again

Tested with Scala REPL 2.10.3 and 2.11.0-M7.

Regards,

Messi

Your class doesn't know its type parameter, apparently. It may be a bug that your t2 method isn't working.

The spec says

A singleton type p .type conforms to the type of the path p.

That's kind of still true here, in so far as Test is just a Test[A] . But since the tag of A is available, you'd think it would use it.

scala> typeTag[a.type].tpe
res8: reflect.runtime.universe.Type = a.type

scala> typeTag[a.type].tpe.widen
res9: reflect.runtime.universe.Type = Test[String]

scala> typeTag[a.type].tpe.widen <:< typeOf[Test[String]]
res10: Boolean = true

scala> typeTag[a.type].tpe <:< typeOf[Test[String]]
res11: Boolean = true

scala> a.t2.tpe
res12: reflect.runtime.universe.Type = Test.this.type

scala> a.t2.tpe.widen
res13: reflect.runtime.universe.Type = Test[A]

The essential fact to remember here is that singleton types are not associated with objects (concrete instances). Rather, they're associated with identifiers .

This means that a single object can have multiple singleton types depending on what identifier it is assigned to. For example:

class C {
  val self = this
  val thistpe = typeOf[this.type]
  type T1 = this.type
  type T2 = self.type
}

val c1 = new C
val c2 = c1
val c3: c1.type = c1

val tpe1 = typeOf[c1.type]
val tpe2 = typeOf[c2.type]
val tpe3 = typeOf[c3.type]
val tpe4 = typeOf[c1.T1]
val tpe5 = typeOf[c1.T2]
val tpe6 = c1.thistpe

In the snippet above, tpe1 , tpe3 and tpe4 will will be recognized as the same types, but the others won't.

In your case, you could try something like this instead:

class C {
  def thisTpe(implicit tag: TypeTag[this.type]) = tag.tpe
}

val c = new C
c.thisTpe =:= typeOf[c.type] // yields true

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM