views:

72

answers:

1

Considering the following Scala snippet:

case class Foo(v1: String, v2: Int, v3: Any)

def inspect(p: Product) =
  (0 until p.productArity).foreach(i => println(p.productElement(i)))

inspect(Foo("Moin", 77, null))

Does the invocation of inspect() here means that reflection is used (in whatever way)?

I'd like to somehow be able to access the fields of a case-class without having to explicitly refer to them, e.g. by foo.v1 and I'd favour a solution that does not require reflection since I expect that it entails some overhead.

+8  A: 

No reflection will be used for the productElement. It's a compiler trick. Adding case before a class doesn't just create a companion object (with apply method and so on, see http://www.scala-lang.org/node/258), it also extends the class from the trait Product. The compiler creates implementations of the abstract methods productArity and productElement.

The output of scalac -print Foo.scala shows it:

... case class Foo extends java.lang.Object with ScalaObject with Product {
...
override def productArity(): Int = 3;
override def productElement(x$1: Int): java.lang.Object = {
  <synthetic> val temp6: Int = x$1;
  (temp6: Int) match {
    case 0 => {
      Foo.this.v1()
    }
    case 1 => {
      scala.Int.box(Foo.this.v2())
    }
    case 2 => {
      Foo.this.v3()
    }
    case _ => {
      throw new java.lang.IndexOutOfBoundsException(scala.Int.box(x$1).toString())
    }
  }
};
...
}

If you want to access to the fields without reflection, you can use the method productElement from the trait Product

scala> case class Foo(v1: String, v2: Int, v3: Any)
defined class Foo

scala> val bar = Foo("Moin", 77, null)
bar: Foo = Foo(Moin,77,null)

scala> bar.productElement(0)
res4: Any = Moin

scala> bar.productElement(1)
res5: Any = 77

scala> bar.productElement(2)
res6: Any = null
Steve
Great answer! Moreover, the `-print` option looks quite useful and I didn't know about it so far. Thanks Steve!
mhs