简体   繁体   中英

Anonymous subclass of a parametric type by the use of ClassTag context bound

Given a concrete class of a given trait

trait Trt {
    val x: Int
}

class C extends Trt {
    val x: Int = 3
}

I'd like to create an object of an anonymous class of a parametric type in order to override the attribute x

abstract class SomeClass[T <: Trt : ClassTag] {
   def f: Unit = {
      val original = new C

      //Is this even possible?
      val withOverridenX = new T { override val x = 42}

      assert(original.x != withOverridenX.x)
   }
}

The problem is that the compiler keeps reporting the following error:

>> Error:(26, 35) class type required but T found

Is instancing anonymous classes extenging parametric types classes even possible?

I know the problem is that T is a type and not a class and I wonder if maybe, thanks to ClassTag bounded contex, it could be possible to instantiate withOverridenX .

You can't instantiate T since it is not known at runtime, just at compile time. The ClassTag would just give you acces to the Class object of T through the runtimeClass method. But with just that, you can't subclass T by calling new , since there's for example no evidence that T has a parameterless constructor.

I found a workaround which allows to do exactly as I want which is: Get an instance of C (or a subclass of C ) with a different value for x than the one given at its declaration time.

Whenever someone wants to abuse a programming language it is usual to turn to reflection. Since version 2.10, Scala offers its own reflection capabilities (aside Java's) so it is possible to change x for withOverridenX :

import scala.reflect.runtime.universe._

abstract class SomeClass[T <: Trt : TypeTag ] {
   def f: Unit = {
      val original = new C
      val withOverridenX = new C

      //This gets the term representation for the attribute 'x'...
      val xTerm = typeOf[T].declaration(newTermName("x")).asTerm

      //... which can be used to reflect the attribute:
      val m = runtimeMirror(getClass.getClassLoader)
      val reflectedC = m.reflect(withOverridenX)
      val reflectedX = reflectedC.reflectField(xTerm)

      reflectedX.set(42)

      assert(original.x != withOverridenX.x)
   }
}

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