Scala Tutorial
Basics
Control Statements
OOP Concepts
Parameterized - Type
Exceptions
Scala Annotation
Methods
String
Scala Packages
Scala Trait
Collections
Scala Options
Miscellaneous Topics
The Uniform Access Principle (UAP) is a software design principle introduced by Bertrand Meyer, the creator of the Eiffel programming language. It states that variables and parameterless methods should be accessed using the same syntax, allowing the client code to remain unaware of whether it's interacting with an attribute or a method. This way, an attribute can be refactored into a method (or vice versa) without changing the client code.
Scala supports the Uniform Access Principle in a straightforward way.
Imagine you have a class that has a field named age
. Later, you decide to change age
from a field to a method without changing the external API.
Here's an illustration:
Using a Field:
class Person { var age: Int = 25 } val person = new Person println(person.age) // Accessing the age field directly
Refactoring to a Method:
If, later on, you decide that age
should be computed based on some other data, you can change it to a method:
class Person { private var _years: Int = 25 def age: Int = _years // age is now a method def age_=(value: Int): Unit = { _years = value } // setter for age } val person = new Person println(person.age) // Still accessing it as if it were a field person.age = 30 // Using the setter method
Notice how the client code println(person.age)
remains the same even after refactoring. This illustrates the Uniform Access Principle in action. The client code doesn't need to know whether age
is a field or a method. This can greatly simplify client code and make it more robust to changes in the underlying implementation.
Scala's support for the Uniform Access Principle ensures that client code can remain consistent and decoupled from the details of whether it's interacting with fields or methods. This principle promotes better encapsulation, ease of refactoring, and clearer code.
In Scala, UAP is inherent in the language design. It treats fields and methods uniformly when accessed, providing a seamless experience for clients.
class MyClass { // Field var myField: String = "Hello" // Method def myMethod: String = "World" } val instance = new MyClass println(instance.myField) // Accessing as a field println(instance.myMethod) // Accessing as a method
In Scala, getters and setters are treated uniformly. You can define them as methods without exposing the implementation details to the client.
class Person { private var _name: String = "" // Getter def name: String = _name // Setter def name_=(newName: String): Unit = _name = newName } val person = new Person person.name = "John" println(person.name)
UAP aligns with core object-oriented principles in Scala, such as encapsulation, inheritance, and polymorphism. It encourages a consistent approach to attribute access regardless of their internal implementation.
trait Animal { def sound: String } class Dog extends Animal { def sound: String = "Woof" } class Cat extends Animal { def sound: String = "Meow" } val dog: Animal = new Dog val cat: Animal = new Cat println(dog.sound) println(cat.sound)
UAP differs from some language features found in other languages. For example, in languages with explicit getters and setters, the client needs to be aware of the implementation details.
// Without UAP class Person { private var _age: Int = 0 // Explicit getter def getAge: Int = _age // Explicit setter def setAge(newAge: Int): Unit = _age = newAge }
UAP aligns well with functional programming principles. In a functional paradigm, data is often represented as immutable objects with uniform access to attributes.
case class Point(x: Double, y: Double) val point = Point(1.0, 2.0) println(point.x) println(point.y)