scalagenericstype-erasureclasstag

No ClassTag available for A - but implicit parameter present


Using scala 2.12.4 I cannot get this code to work since it says

[error] .../src/main/scala/effect.scala:32:11: No ClassTag available for A

[error] Effect(effectDefinition)

[error] ^

[error] one error found

[error] (compile:compileIncremental) Compilation failed

here is the (simplified) code. the reason i need the class tag is to do a filtering later in the code (installEffect).

import scala.reflect.ClassTag

package object effect {

  type EffectDefinition[A <: EffectBearing[A]] = A => Unit

  case class Effect[A <: EffectBearing[A]](fx: A => Unit)(implicit tag: ClassTag[A]) {
    def effectedType: Class[A] = tag.runtimeClass.asInstanceOf
  }

  trait EffectBearing[This <: EffectBearing[This]] {
    def installEffect(effect: Effect[This]): Unit = {
      effect.fx(this.asInstanceOf[This])
    }
  }

  trait EffectPropagating {

    def installEffect[T<: EffectBearing[T]](effect: Effect[T], typ: Class[T]): Unit =
      find(typ).foreach(_.installEffect(effect))

    protected def find[T <: EffectBearing[T]](typ: Class[T]): Set[T]
  }

  class Foo extends EffectBearing[Foo] {}

  val fxFoo: EffectDefinition[Foo] = print(_)

  def translate[A <: EffectBearing[A]](effectDefinition: EffectDefinition[A]): Effect[A] =
    Effect(effectDefinition)

  val fx = translate(fxFoo)

}

ps: is the usage of

tag.runtimeClass.asInstanceOf

very bad? I couldn't get around that cast


Solution

  • You have the following method:

    def translate[A <: EffectBearing[A]](effectDefinition: EffectDefinition[A]): Effect[A] =
      Effect(effectDefinition)
    

    The Effect constructor requires an implicit ClassTag[A] but here A is a type parameter so the compiler doesn't know which concrete class it will be. And there is no ClassTag context bound on A in translate, so the compiler will not be able to find an implicit ClassTag[A].