Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to define a constructor-local variable in Scala?

The following code is taken from Programming in Scala book by Martin Odersky et al. which defines a rational type:

class Rational(n: Int, d: Int) { 
  require(d != 0)
  private val g = gcd(n.abs, d.abs)
  val numer = n / g 
  val denom = d / g
  ...
  private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b)
}

Here the value g is only used when the implicit constructor initializes fields numer and denom. Suppose programmer knows that it wont be used anywhere else. In the above case it is still accessible after construction of the Rational object. Which means it will also occupy space since is a private field rather than being a local variable to the constructor.

My question is how do I change this code so that g is only used while construction and then thrown away?

like image 385
ciuncan Avatar asked Jan 12 '12 22:01

ciuncan


1 Answers

In this case, how about something like this?

class Rational(n: Int, d: Int) {
  require(d != 0)
  val (numer, denom) = {
    val g = gcd(n.abs, d.abs)
    (n / g, d / g)
  }
  private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b)
}

EDIT: This also creates an extra field that holds a tuple, as shown by running javap on the compiled class (thanks, Alexey):

public class Rational extends java.lang.Object implements scala.ScalaObject{
    private final scala.Tuple2 x$1; // actually unwanted!
    private final int numer;
    private final int denom;
    public int numer();
    public int denom();
    private int gcd(int, int);
    public Rational(int, int);
}

In other cases, I sometimes use the locally block to avoid turning every val into a field:

class A {
  locally {
    val value1 = // ...
    val value2 = // ...
  }
}
like image 135
Jean-Philippe Pellet Avatar answered Sep 28 '22 01:09

Jean-Philippe Pellet