Scala Tutorial

Basics

Control Statements

OOP Concepts

Parameterized - Type

Exceptions

Scala Annotation

Methods

String

Scala Packages

Scala Trait

Collections

Scala Options

Miscellaneous Topics

Getters and Setters in Scala

In Scala, classes come with built-in support for getters and setters, making it easy to encapsulate fields. Unlike Java, where you'd typically write explicit getter and setter methods, Scala provides a more concise way of handling this.

Basic Getters and Setters

When you declare a class variable as var, Scala automatically generates getters and setters for it:

class Person {
  var name: String = _
}

For the above code:

  • Getter is: def name: String
  • Setter is: def name_=(value: String): Unit

You can use them as:

val person = new Person
person.name = "Alice"  // calls the setter
println(person.name)   // calls the getter

Custom Getters and Setters

If you need custom behavior in your getters and setters, you can define them explicitly:

class Person {
  private var _age: Int = 0
  
  // Getter
  def age: Int = _age
  
  // Setter
  def age_=(value: Int): Unit = {
    if (value > _age) {
      _age = value
    }
  }
}

In the above code:

  • The actual age field is made private and named _age.
  • A custom getter age just returns the _age.
  • A custom setter age_= only updates the age if the new value is greater than the current age.

Using Properties with val

If you declare a class property using val, it becomes read-only, and only a getter is generated:

class Person {
  val birthYear: Int = 1990
}

In this case, you can read birthYear, but you can't change it after the object is constructed.

Private Getters and Setters

If you want to make the getter and/or setter private, you can use access modifiers:

class Person {
  private var _name: String = _
  
  def name: String = _name  // Public getter
  
  private def name_=(value: String): Unit = { // Private setter
    _name = value
  }
}

In this example, the setter for name is private, so it cannot be accessed outside of the Person class.

Conclusion

Scala's approach to getters and setters is concise and expressive. It eliminates boilerplate while still offering the flexibility to customize the behavior when needed. This is another example of how Scala blends object-oriented and functional programming paradigms to offer a powerful programming model.

  1. Scala class properties and accessors:

    • Description: Properties in Scala classes define the data members, and accessors provide a way to read their values.
    • Code Example:
      class Person(var name: String, var age: Int)
      
      val person = new Person("Alice", 25)
      println(person.name) // Accessing the property
      
  2. Defining getters and setters in Scala:

    • Description: Getters and setters in Scala are automatically generated for var properties, allowing access and modification.
    • Code Example:
      class Person(var name: String, var age: Int)
      val person = new Person("Bob", 30)
      person.age = 35 // Using the setter
      
  3. Custom getter and setter methods in Scala:

    • Description: Custom getter and setter methods provide control over property access and modification.
    • Code Example:
      class Person(private var _age: Int) {
        def age: Int = _age
        def age_=(newAge: Int): Unit = {
          if (newAge >= 0) _age = newAge
        }
      }
      
      val person = new Person(25)
      person.age = 30 // Using the custom setter
      
  4. Immutable properties in Scala:

    • Description: Using val instead of var creates immutable properties that cannot be modified after initialization.
    • Code Example:
      class Circle(val radius: Double)
      
      val circle = new Circle(5.0)
      // circle.radius = 7.0 // Error: Cannot reassign to val
      
  5. Using case classes for automatic getters and setters:

    • Description: Case classes in Scala automatically generate getters and equals methods, providing concise and immutable structures.
    • Code Example:
      case class Point(x: Double, y: Double)
      val origin = Point(0.0, 0.0)
      println(origin.x) // Automatic getter
      
  6. Scala val vs. var and property mutability:

    • Description: val declares immutable properties, while var declares mutable properties.
    • Code Example:
      class Student(val name: String, var age: Int)
      val student = new Student("Charlie", 21)
      // student.name = "David" // Error: Cannot reassign to val
      
  7. Getter and setter visibility in Scala:

    • Description: Getters and setters can have different access modifiers, controlling their visibility.
    • Code Example:
      class Person {
        private var _age: Int = 0
        def age: Int = _age
        private def age_=(newAge: Int): Unit = {
          if (newAge >= 0) _age = newAge
        }
      }
      
  8. Access control for getters and setters in Scala:

    • Description: Access modifiers like private, protected, and public can be used to control access to properties.
    • Code Example:
      class BankAccount(private var balance: Double) {
        def deposit(amount: Double): Unit = {
          if (amount > 0) balance += amount
        }
        def getBalance: Double = balance
      }
      
  9. Lazy initialization with getters in Scala:

    • Description: Lazy properties are initialized only when accessed for the first time, reducing unnecessary computations.
    • Code Example:
      class ExpensiveResource {
        // Assume expensive initialization
      }
      
      class MyClass {
        lazy val resource: ExpensiveResource = new ExpensiveResource
      }
      
  10. Property naming conventions in Scala:

    • Description: Scala follows naming conventions, using camelCase for property names and camelCase_ for private properties.
    • Code Example:
      class Employee(private val employeeId: String, var salary: Double)
      
  11. Overriding getters and setters in Scala:

    • Description: Getters and setters can be explicitly overridden in subclasses, providing custom behavior.
    • Code Example:
      class CelsiusTemperature(var celsius: Double) {
        def fahrenheit: Double = celsius * 9 / 5 + 32
        def fahrenheit_=(f: Double): Unit = {
          celsius = (f - 32) * 5 / 9
        }
      }
      
  12. Property observers and getters in Scala:

    • Description: Property observers (didSet and willSet in Swift) are not directly available in Scala. However, custom logic can be added to getters and setters.
    • Code Example:
      class Temperature(private var _celsius: Double) {
        def celsius: Double = _celsius
        def celsius_=(newCelsius: Double): Unit = {
          // Custom logic
          _celsius = newCelsius
        }
      }
      
  13. Scala self-types and property access:

    • Description: Self-types express dependencies between traits and allow access to properties of the dependent trait.
    • Code Example:
      trait Logger {
        def log(message: String): Unit
      }
      
      trait UserService {
        this: Logger =>
      
        def performAction(): Unit = {
          log("Action performed")
        }
      }