How to prevent getter and setter methods from being generated in Scala classes

This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 4.7, “How to prevent getter and setter methods from being generated in Scala classes.”

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