0

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

Community
  • 1
  • 1
winson
  • 388
  • 1
  • 9

1 Answers1

4

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].

Jasper-M
  • 14,966
  • 2
  • 26
  • 37
  • Thanks, adding a ClassTag bound to translate makes the whole thing compile. But I don't understand why. Can you point me to some resources that explains this? – winson Nov 19 '17 at 18:05
  • Basically, the code inside the `translate` method doesn't know the class of `A` at runtime, it only knows the type `A` at compile time. By adding the `ClassTag` bound on `A` you ask the compiler to provide a `ClassTag` at runtime for your program. The compiler will generate a `ClassTag` at the point where it knows the concrete class and pass it implicitly through all your methods so that your program can access the concrete class when it needs it. – Rich Dougherty Nov 19 '17 at 19:11
  • interestingly it also works when transformed the type deifnition "EffectDefinition" into a class with an implicit class tag. Anyway, i should read into that and mark the answer as accepted for now – winson Nov 20 '17 at 22:02