views:

102

answers:

2

I have a number of classes that look like this:

class Foo(val:BasicData) extends Bar(val) {
    val helper = new Helper(val)
    val derived1 = helper.getDerived1Value()
    val derived2 = helper.getDerived2Value()
}

...except that I don't want to hold onto an instance of "helper" beyond the end of the constructor. In Java, I'd do something like this:

public class Foo {
  final Derived derived1, derived2;
  public Foo(BasicData val) {
     super(val);
     Helper helper = new Helper(val);
     derived1 = helper.getDerived1Value();
     derived2 = helper.getDerived2Value();
  }
}

So how do I do something like that in Scala? I'm aware of creating a helper object of the same name of the class with an apply method: I was hoping for something slightly more succinct.

+5  A: 

You could use a block to create a temporary helper val and return a tuple, like this:

class Foo(v: BasicData) extends Bar(v) {
  val (derived1, derived2) = {
    val helper = new Helper(v)
    (helper.getDerived1Value(), helper.getDerived2Value())
  }
}
Don Mackenzie
I think this is perfect as long as Scala can infer the types successfully...
Robert Fischer
Thanks Robert, you can annotate the types of the vals if you are concerned about their types:val (x: Int, y: String) = {...}
Don Mackenzie
See the notice below.
Robert Fischer
+4  A: 

Better look at the javap output (including private members) before you conclude this has side-stepped any fields for the Tuple2 used in the intermediate pattern-matching.

As of Scala 2.8.0.RC2, this Scala code (fleshed out to compile):

class BasicData
{
  def basic1: Int = 23
  def basic2: String = "boo!"
}

class Helper(v: BasicData)
{
  def derived1: Int = v.basic1 + 19
  def derived2: String = v.basic2 * 2
}

class Bar(val v: BasicData)

class   Foo(v: BasicData)
extends Bar(v)
{
  val (derived1, derived2) = {
    val helper = new Helper(v)
    (helper.derived1, helper.derived2)
  }
}

Produces this Foo class:

% javap -private Foo
public class Foo extends Bar implements scala.ScalaObject{
    private final scala.Tuple2 x$1;
    private final int derived1;
    private final java.lang.String derived2;
    public int derived1();
    public java.lang.String derived2();
    public Foo(BasicData);
}
Randall Schulz
Looks like a bug, actually.
Daniel
Previous discussion of the problem: http://scala-programming-language.1934581.n4.nabble.com/Temporary-Values-in-Constructors-Retained-As-Fields-td1946886.html#a1946886
retronym
Odersky: "There should be an optimization that turns private[this] variables that are only used for class initialization into constructor-local variables. It would be relatively easy to do that, I think. But it has not yet been done. "
retronym