Overview

This post looks into primary and auxiliary constructors for Scala classes.

Scala Classes 2

A Scala class can have as many constructors as we want. A Scala class has a so called primary constructor. Additionally, a class can have any number of auxiliary constructors.

Primary constructor

A Scala class has a so called primary constructor. The primary constructor is not defined with a this method. This is interwoven with the class definition [1].

class Person(val name: String, val age: Int){
    
    
}
defined class Person

Parameters of the primary constructor turn into fields that are initialized with the construction parameters.

val p = new Person("Alex", 10)
p: Person = ammonite.$sess.cmd10$Helper$Person@62b0e31f
println(p.name + " has age " + p.age)
Alex has age 10

The primary constructor executes all statements in the class definition. This is shown below

class AnotherClass(val val1: Double, val val2: Int){
    
    show()
    
    def show()={
        println(val1 + ", " + val2)
    }
    
}
defined class AnotherClass
val cls = new AnotherClass(20.0, 10)
20.0, 10
cls: AnotherClass = ammonite.$sess.cmd13$Helper$AnotherClass@1ea96977

The show() function call is a part of the primary constructor. It will be called every time a new object is created [1]. Moreover, if there are no parameters after the class name, then the class has a primary constructor with no parameters. That constructor simply executes all statements in the body of the class [1].

The primary constructor of the AnotherClass declares and initializes the following fields

val val1: Double
val val2: Int

Since the primary constructor parameters are declared with the private keyword, the getter function is public. Moreover only a getter is generated as both variables are declared with val.

Construction parameters can also be regular method parameters, without val or var . How these parameters are processed depends on their usage inside the class[1].

If a parameter without val or var is used inside at least one method, it becomes a field.

class AnotherClass_2(val1: Double, val2: Int){
    
    def description = val1 + " , " + val2 
}
defined class AnotherClass_2

The primary constructor above, declares and initializes immutable fields val1 and val2 that are object-private i.e. instances of the same class do not have access to these fields of another instance from the same class.

Otherwise, the parameter is not saved as a field. Meaning it is just a regular parameter that can be accessed in the code of the primary constructor [1].

Finally, sometimes we may want to declare a primary constructor as private. We can do so as shown below

class AnotherClass_3 private(val1: Double, val2: Int){
    
    def description = val1 + " , " + val2 
}
defined class AnotherClass_3

A class user must then use an auxiliary constructor to construct a AnotherClass_3 object [1].

Auxiliary constructors

Auxiliary constructs are called this [1]. Each such constructor should start with a call to a previously defined auxiliary constructor or the primary constructor.

class MyCls{
    private var name = ""
    private var age = 0
    
    def this(name: String){
        // first call primary constructor
        this()
        this.name = name
        
    }
    
    def this(name: String, age: Int){
        this(name)
        
        //set also the age
        this.age = age
    }
}
defined class MyCls

The first auxiliary constructor, i.e. this(name: String), calls the empty primary construtor this(). For a class we do not define a primary constructor has a primary constructor with no arguments [1].

val cls1 = new MyCls
val cls2 = new MyCls("Alex")
val cls3 = new MyCls("Alex", 10)
cls1: MyCls = ammonite.$sess.cmd17$Helper$MyCls@78f51c1b
cls2: MyCls = ammonite.$sess.cmd17$Helper$MyCls@4cf2a04c
cls3: MyCls = ammonite.$sess.cmd17$Helper$MyCls@5ece3c6c

References

  1. Cay Horstmann, Scala for the Impatient 1st Edition