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> val x = 42
x: Int = 42
If you try to assign another value to it, an error results.
scala> x = 2
<console>:8: error: reassignment to val
x = 2
^
You can declare a mutable property with the var
keyword, like this.
scala> var y = 42
y: Int = 42
Of course you can assign another value of the same type to mutable variables.
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> 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/
.
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.
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.
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> 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/
.
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.
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> 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> 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
.
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> 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> 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.
© Copyright 1994-2024 Michael Slinn. All rights reserved.
If you would like to request to use this copyright-protected work in any manner,
please send an email.
This website was made using Jekyll and Mike Slinn’s Jekyll Plugins.