7

Scala: Access to class parameters vs access to object fields

 2 years ago
source link: https://www.codesd.com/item/scala-access-to-class-parameters-vs-access-to-object-fields.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Scala: Access to class parameters vs access to object fields

advertisements

I am coming from Java background and new to Scala, currently going through the book 'Programming in Scala'.

There is an example in the book as below:

class Rational(n: Int, d: Int) { // This won't compile
  require(d != 0)
  override def toString = n + "/" + d

  def add(that: Rational): Rational = new Rational(n * that.d + that.n * d, d * that.d)
}

However, given this code the compiler complains:

error: value d is not a member of Rational
       new Rational(n * that.d + that.n * d, d * that.d)
                             ^
error: value n is not a member of Rational
       new Rational(n * that.d + that.n * d, d * that.d)
                                      ^
error: value d is not a member of Rational
       new Rational(n * that.d + that.n * d, d * that.d)
                                                      ^

The explanation says:

Although class parameters n and d are in scope in the code of your add method, you can only access their value on the object on which add was invoked. Thus, when you say n or d in add's implementation, the compiler is happy to provide you with the values for these class parameters. But it won't let you say that.n or that.d because that does not refer to the Rational object on which add was invoked. To access the numerator and denominator on that, you'll need to make them into fields.

Also the correct implementation is given as below:

class Rational(n: Int, d: Int) {
  require(d != 0)
  val numer: Int = n
  val denom: Int = d

  override def toString = numer + "/" + denom

  def add(that: Rational): Rational =
    new Rational(
      numer * that.denom + that.numer * denom,
      denom * that.denom
    )
}

I tried to understand this many times, but still not clear.

I already have the n and d parameters at class level. I am able to access them in add method. I am passing another Rational object to the add method. It should also be having n and d, right?

What is wrong with that.n and that.d? Why do I need to take the parameters in fields?

Also, the overridden toString method is simply taking n and d, how does that not fail?

I may sound stupid, but really need to understand this clearly for better fundamentals before I move ahead.


Parameters passed to a class constructor defaults to private members and thus are are available to all the class code (as seen in the toString override) but they are not accessible as instance members (so that.d doesn't work).

You can tell the compiler not to use the default.

class Rational(val n: Int, val d: Int) { // now it compiles
  ...

Alternatively, arguments passed to a case class default to instance members.

case class Rational(n: Int, d: Int) { // this also compiles
  ...




About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK