11

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?

ciuncan
  • 1,062
  • 2
  • 11
  • 25
  • 2
    This is one of those "icky points" in Scala. Imagine that if the given constructor object was only used to extract some arbitrary information: having it around forever would keep it from being eligible for reclamation even if only a small subset of information was required. I think there is a "pre-class body" syntax, but I can't recall what it is. –  Jan 12 '12 at 22:15
  • @pst Thanks for this quick edit I was doing so meanwhile. Yours look better though. :) – ciuncan Jan 12 '12 at 22:16
  • 2
    If anyone has any links regarding this "pre-class body" syntax that pst mentions, I'd be interested to hear about it. – Luigi Plinge Jan 13 '12 at 01:16
  • 2
    See questions http://stackoverflow.com/questions/1218872/avoiding-scala-memory-leaks-scala-constructors and http://stackoverflow.com/questions/1118669/how-do-you-define-a-local-var-val-in-the-primary-constructor-in-scala – Alexey Romanov Jan 13 '12 at 05:46

1 Answers1

10

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 = // ...
  }
}
Jean-Philippe Pellet
  • 59,296
  • 21
  • 173
  • 234
  • Thank you this could possibly be th best solution. I also learned about "locally" block, so thanks again. – ciuncan Jan 12 '12 at 22:31
  • Can I also use values or variables defined in locally block outside of it, just in that class body? Or they are just local to locally block? – ciuncan Jan 12 '12 at 22:35
  • 2
    @ciuncan Anything declared in a code block (i.e. delimited by curly braces) is only accessible within that block. `locally` is just a convenience method for avoiding semicolon inference issues (not a keyword), so can't change this. See http://stackoverflow.com/questions/3237727/what-does-predef-locally-do-and-how-is-it-different-from-predef-identity for info on `locally`. – Luigi Plinge Jan 13 '12 at 01:11
  • 3
    Except now you have a different private field holding the tuple `(numer, denom)`, unless this has changed in later Scala versions: http://stackoverflow.com/questions/1218872/avoiding-scala-memory-leaks-scala-constructors – Alexey Romanov Jan 13 '12 at 05:49
  • @AlexeyRomanov thank you for your comment. And also thank you for pointing at the similar questions which I had failed to find while searching. There is sure a lot to learn about Scala, too much detail and feature exist. This makes the language more interesting. :) – ciuncan Jan 14 '12 at 11:24
  • http://stackoverflow.com/a/1451024/294325 this solution seemed the best to me so far. What are your opinions? – ciuncan Jan 14 '12 at 11:32