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!