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?

4
  • 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. Commented Jan 12, 2012 at 22:15
  • @pst Thanks for this quick edit I was doing so meanwhile. Yours look better though. :) Commented Jan 12, 2012 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. Commented Jan 13, 2012 at 1:16
  • 2
    See questions stackoverflow.com/questions/1218872/… and stackoverflow.com/questions/1118669/… Commented Jan 13, 2012 at 5:46

1 Answer 1

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 = // ...
  }
}
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you this could possibly be th best solution. I also learned about "locally" block, so thanks again.
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 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 stackoverflow.com/questions/3237727/… for info on locally.
Except now you have a different private field holding the tuple (numer, denom), unless this has changed in later Scala versions: stackoverflow.com/questions/1218872/…
@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. :)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.