Scala Tutorial
Basics
Control Statements
OOP Concepts
Parameterized - Type
Exceptions
Scala Annotation
Methods
String
Scala Packages
Scala Trait
Collections
Scala Options
Miscellaneous Topics
In Scala, classes can have one primary constructor and one or more auxiliary (or secondary) constructors. The primary constructor is intertwined with the class definition and executes the statements in the class body, while auxiliary constructors are defined using the def this(...)
syntax. These auxiliary constructors are helpful when you want to create multiple ways to instantiate objects but still reuse a single primary constructor's logic.
Here's how you can use auxiliary constructors in Scala:
The primary constructor's parameters are placed right after the class name:
class Person(val name: String, val age: Int) { println(s"Primary constructor: Name: $name, Age: $age") }
Auxiliary constructors are defined using the this
keyword:
class Person(val name: String, val age: Int) { // Primary constructor logic println(s"Primary constructor: Name: $name, Age: $age") // First auxiliary constructor: Only name provided def this(name: String) { this(name, 0) // Calling primary constructor println("First auxiliary constructor") } // Second auxiliary constructor: No parameters def this() { this("Unknown", 0) // Calling primary constructor println("Second auxiliary constructor") } }
You can create objects using any of these constructors:
val person1 = new Person("John", 25) // Uses primary constructor val person2 = new Person("Alice") // Uses first auxiliary constructor val person3 = new Person() // Uses second auxiliary constructor
Each auxiliary constructor must begin with a call to either the primary constructor (using this(...)
) or another auxiliary constructor. This ensures that the primary constructor is always executed, no matter which constructor is used to create the object.
Auxiliary constructors cannot be called directly from other classes; they are always used via object instantiation.
The primary constructor's parameters can be turned into class fields by prefixing them with val
or var
. Auxiliary constructors do not have this capability; they are merely methods.
Auxiliary constructors in Scala offer a way to provide multiple pathways for object instantiation. However, case classes and default argument values can sometimes negate the need for auxiliary constructors, making object creation more concise and intuitive.
Initializing Objects with Auxiliary Constructors:
You can define auxiliary constructors using the this
keyword and call the primary constructor or another auxiliary constructor using this()
.
class Person(var name: String, var age: Int) { def this() { this("Unknown", 0) } def this(name: String) { this(name, 0) } } val person1 = new Person("Alice", 25) val person2 = new Person() val person3 = new Person("Bob")
Default Parameters and Auxiliary Constructors in Scala:
You can use default parameters in the primary constructor to simplify the definition of auxiliary constructors.
class Person(var name: String = "Unknown", var age: Int = 0) { def this(name: String) { this(name, 0) } } val person1 = new Person("Alice", 25) val person2 = new Person() val person3 = new Person("Bob")
Chaining Constructors in Scala:
Constructors in Scala can be chained, allowing one constructor to call another using this()
.
class Person(var name: String, var age: Int) { def this() { this("Unknown", 0) } def this(name: String) { this(name, 0) } }
Overloading Constructors in Scala:
Overloading constructors involves defining multiple constructors with different parameter lists.
class Point(var x: Int, var y: Int) { def this() { this(0, 0) } def this(x: Int) { this(x, 0) } } val point1 = new Point(1, 2) val point2 = new Point() val point3 = new Point(5)
Common Pitfalls with Auxiliary Constructors in Scala:
Be cautious with the order of initialization and potential redundancy when using auxiliary constructors. Avoid unnecessary complexity and ensure that all paths lead to a fully initialized object.
class Rectangle(var width: Int, var height: Int) { def this() { // Incorrect: Calls primary constructor with default values, then sets width to 10 this(10, 0) width = 10 } }
In the example above, the auxiliary constructor incorrectly calls the primary constructor and then redundantly sets the width
to 10, leading to unexpected behavior.