Search code examples
scalareflectionscala-2.11

Compiler doesn't generate a field for implicit val when an implicit val with the same type is present in the superclass


I have a class Foo defined as follows:

class Elem[A]

abstract class BaseDef[T](implicit val selfType: Elem[T])

case class Foo[A, T]()(implicit val eA: Elem[A], val eT: Elem[T]) extends BaseDef[A]

To my surprise, getDeclaredFields does not include eA:

object Test extends App {
  private val fields = classOf[Foo[_, _]].getDeclaredFields

  println(fields.mkString("\n"))
  assert(fields.exists(_.getName == "eA"))
}

produces

private final scalan.Elem scalan.Foo.eT    
Exception in thread "main"
java.lang.AssertionError: assertion failed
    at scala.Predef$.assert(Predef.scala:151)
    at scalan.Test$.delayedEndpoint$scalan$Test$1(JNIExtractorOps.scala:15)
    at scalan.Test$delayedInit$body.apply(JNIExtractorOps.scala:11)

Is there an explanation for this or is this a known bug (Scala version is 2.11.7)? I can access eA from outside the class.

It seems the compiler decides it can reuse selfType field for eA, which would be great if it didn't break access to eA in scala-reflect.


Solution

  • Reply from Jason Zaugg on scala-user:

    The compiler avoids redundant fields in subclasses if it statically determines that the value is stored in a field in a super class that exposes it via an accessible accessor.

    To prevent this, you might be able to change the superclass constructor by removing the val keyword and add another val to that class that stores the parameter.