4.7. Preventing Getter and Setter Methods from Being Generated

Problem

When you define a class field as a var, Scala automatically generates getter and setter methods for the field, and defining a field as a val automatically generates a getter method, but you don’t want either a getter or setter.

Solution

Define the field with the private or private[this] access modifiers, as shown with the currentPrice field in this example:

class Stock {

  // getter and setter methods are generated
  var delayedPrice: Double = _

  // keep this field hidden from other classes
  private var currentPrice: Double = _
}

When you compile this class with scalac, and then disassemble it with javap, you’ll see this interface:

// Compiled from "Stock.scala"
public class Stock extends java.lang.Object implements scala.ScalaObject{
  public double delayedPrice();
  public void delayedPrice_$eq(double);
  public Stock();
}

This shows that getter and setter methods are defined for the delayedPrice field, and there are no getter or setter methods for the currentPrice field, as desired.

Discussion

Defining a field as private limits the field so it’s only available to instances of the same class, in this case instances of the Stock class. To be clear, any instance of a Stock class can access a private field of any other Stock instance.

As an example, the following code yields true when the Driver object is run, because the isHigher method in the Stock class can access the price field both (a) in its object, and (b) in the other Stock object it’s being compared to:

class Stock {
  // a private field can be seen by any Stock instance
  private var price: Double = _
  def setPrice(p: Double) { price = p }
  def isHigher(that: Stock): Boolean = this.price > that.price
}

object Driver extends App {

  val s1 = new Stock
  s1.setPrice(20)

  val s2 = new Stock
  s2.setPrice(100)

  println(s2.isHigher(s1))

}

Object-private fields

Defining a field as private[this] takes this privacy a step further, and makes the field object-private, which means that it can only be accessed from the object that contains it. Unlike private, the field can’t also be accessed by other instances of the same type, making it more private than the plain private setting.

This is demonstrated in the following example, where changing private to private[this] in the Stock class no longer lets the isHigher method compile:

class Stock {
  // a private[this] var is object-private, and can only be seen
  // by the current instance
  private[this] var price: Double = _

  def setPrice(p: Double) { price = p }

  // error: this method won't compile because price is now object-private
  def isHigher(that: Stock): Boolean = this.price > that.price
}

Attempting to compile this class generates the following error:

Stock.scala:5: error: value price is not a member of Stock
  def isHigher(that: Stock): Boolean = this.price > that.price
                                                    ^
one error found

Get Scala Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.