Sometimes we want to hide/protect our variables — the classic concept of encapsulation in object oriented programming.
We’d like to write a Scala class to manage someone’s age. In particular, we’d like to:
– lie on our age if we are not teens anymore (you never know!)
– put some validation to avoid negative age values
Our first try is following:
package girlcoding.tutorial
class MyAge {
var age: Int = _
override def toString = s"I am $age years old"
}
This compiles, but it doesn’t respect the given requirements!
val myAge = new MyAge
myAge.age = 30
println(myAge); // it prints: "I am 30 years old"
// it should be lying here!
myAge.age = -110
println(myAge); // it prints: "I am -110 years old"
// it should not be possible!
After some research, we discover that our so needed setters and getters are actually just hidden! In fact, the compiler transforms MyAge code into the following:
package girlcoding.tutorial
class MyAge {
private[this] var a = _
def age: Int = a // getter
def age_= (x: Int) { a = x } // setter
override def toString = s"I am $a years old"
}
Let’s use this information to our advantage and deliver our requirements:
package girlcoding.tutorial
class MyAge {
private[this] var realAge: Int = _
def age = {
if (realAge > 19) realAge - 5
else realAge
}
def age_= (a: Int) {
require(a <= 0, "Age cannot be negative!")
realAge = a
}
override def toString = s"I am $age years old"
}
Note that the variable realAge is completely hidden and it cannot be accessed from outside, so no one will know our little secret! 😉
We can now play with our MyAge class — and lie when needed.
val myAge = new MyAge
myAge.age = 10
println(myAge) // it prints "I am 10 years old"
// still young, no need to lie...
myAge.age = 30
println(myAge); // it prints: "I am 25 years old"
// lier! myAge.age was actually set to 30
myAge.age = -110
// throws java.lang.IllegalArgumentException:
// requirement failed: Age cannot be negative!