Mike Slinn

Setters, Getters and the Uniform Access Principle

— Draft —

Published 2014-01-02. Last modified 2016-01-25.
Time to read: 3 minutes.

This lecture discusses Scala setters and getters and the Uniform Access Principle.

Quick Review

You can declare an immutable property with the val keyword, like this.

Scala REPL
scala> val x = 42
x: Int = 42

If you try to assign another value to it, an error results.

Scala REPL
scala> x = 2
<console>:8: error: reassignment to val
x = 2
^

You can declare a mutable property with the var keyword, like this.

Scala REPL
scala> var y = 42
y: Int = 42

Of course you can assign another value of the same type to mutable variables.

Scala REPL
scala> y = 3
y: Int = 3

You can define a method with the def keyword. This echo method is declared to return Unit. This writing style is a good practice, because it tells the reader that nothing is expected to be returned, which implies that this method has side effects. println returns Unit and since it is the last expression in the method body, the value returned by println is the value returned by the method. Scala 2.12 enforces this writing style.

Scala REPL
scala> def echo(what: String): Unit = println(what)
echo: (what: String)Unit
scala>
echo("Hi there!") Hi there!

Setters and Getters

The convention for Scala getters is to create a method named after the property with no arguments. Scala setters are methods that are also named after the property, with _= appended. Let’s look at some sample Scala code, which can be found in courseNotes/src/main/scala/GetSetDemo.scala.

Let’s look at some sample Scala code, which can be found in courseNotes/src/main/scala/GetSetDemo.scala.

Scala code
class GetSetExample1 {
  private var pn = ""
def name = pn // getter
// setter can be called three ways, shown below def name_=(n: String): Unit = { pn = n } }

Unlike Java, var and val values must be assigned a value when they are declared, unless they are defined within an abstract trait or class.

Let’s define an entry point called GetSetDemo1 that can be invoked as a console application.

Scala code
object GetSetDemo1 extends App {
  val x = new GetSetExample1
  x.name_=("fred")    // although this syntax is possible
  x.name = "george"   // this syntax is more commonly used
  println(x.name)
}

Scala implements assignment (=) as a method, called $eq(), and also follows this convention for setters. The above is equivalent to the following Scala code, which is simpler.

Scala code
class GetSetExample2 {
  var name = ""
}

object GetSetDemo2 extends App {
  val x = new GetSetExample2
  x.name_=("mary")
  x.name_$eq("mary")
  x.name = "lucy"
  println(x.name)
}

Let’s decorate Frog2’s primary constructor arguments with var and val so they become properties.

Scala REPL
scala> class Frog2(val canSwim: Boolean, var
numLegs: Int, val breathesAir: Boolean) extends Animal(numLegs, breathesAir) {
     |   override def toString = s"Frog2 canSwim=$canSwim, numLegs=$numLegs, breathesAir=$breathesAir"
     | }
defined class Frog2
scala>
val tadpole = new Frog2(true, 0, false) tadpole: Frog2 = Frog2@794d6ef3
scala>
tadpole.numLegs res7: Int = 0
scala>
tadpole.breathesAir res8: Boolean = false

Uniform Access Principle

The code for this section is provided in courseNotes/src/main/scala/Uniform.scala.

It is convenient but incorrect to think of var and val as fields. Scala enforces the Uniform Access Principle by making it impossible to refer to a field directly.

The Uniform Access Principle was put forth by Bertrand Meyer. It states "All services offered by a module should be available through a uniform notation, which does not betray whether they are implemented through storage or through computation". This principle applies generally to object-oriented programming languages. In simpler form, it states that there should be no difference between working with an attribute, precomputed property, or method/query.
 – Wikipedia

Accesses to all properties of Scala objects and class instances are made through getters and setters. When the Scala compiler encounters a val or var in source code, it emits a property and a getter method for the property. For a var, the Scala compiler also emits a setter method for the property. In this example, the name property is defined as an immutable String.

Scala REPL
scala> class Person1 { val name = "Fred Flintstone" }
defined class Person1
scala>
val person1 = new Person1 person1: Person1 = Person1@7ddaca36
scala>
println(person1.name) Fred Flintstone

The name method in the Person2 class returns identical results as the name property in Person1. In fact, judging by the returned value and type, there is no difference between Person1.name and Person2.name. This is the essence of the Uniform Access Principle.

Scala REPL
scala> class Person2 { def name = "Fred Flintstone" }
defined class Person2
scala>
val person2 = new Person2 person2: Person2 = Person2@26fda07e
scala>
println(person2.name) Fred Flintstone

The only difference is that the def is evaluated every time it is invoked, while the val is evaluated once.

Scala getters and setters are methods, and they are defined in the same namespace as all other methods.

This means you cannot have a property with the same name as a method. This also means that when subclassing, a val or a var can override a def.

For example, here we see a val overriding a def.

Scala code
abstract class AbstractPerson {
  def name: String
  def printName() = println(name)
}
class Person3 extends AbstractPerson { val name = "Jumping Jack Flash" }

Let’s see what the REPL shows us:

Scala REPL
scala> val person3 = new Person3
person3: Person3 = Person3@19661df0
scala>
person3.printName() Jumping Jack Flash

Here we see a var overriding a def:

class Person4 extends AbstractPerson { var name = "Jane Danger" }

Let’s see what the REPL shows us.

Scala REPL
scala> val person4 = new Person4
person4: Person4 = Person4@33d15244
scala>
person4.printName() Jane Danger

Note that a method defined with def cannot override a var or val. So this means for maximum flexibility you should declare properties in base types with def, so implementations can optimize by overriding with val or var when appropriate.


* indicates a required field.

Please select the following to receive Mike Slinn’s newsletter:

You can unsubscribe at any time by clicking the link in the footer of emails.

Mike Slinn uses Mailchimp as his marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp’s privacy practices.