Start learning free

LESSON 206 OF 414 · FUNCTIONS & CLASSES

Constructors in Scala: Primary and Auxiliary

Lesson Read the full explanation

TL ; DR:

  • A constructor is a special method that runs automatically when you create an object. It's used to set up the object's initial state.


  • In Scala, the class header is the constructor: list the fields as var parameters and Scala creates and sets them when the object is created:

    class Dog(var name: String, var age: Int)
    

  • Then create objects with arguments: Dog("Rex", 4) — the constructor fills in the fields for you.



Full lesson:

In the previous lesson you set fields after creating the object:

val dog = Dog()
dog.name = "Rex"
dog.age = 4

That works, but it's noisy and easy to forget. Constructors let you initialize the fields the moment Dog(...) is called.


Defining a constructor

A Scala class has a primary constructor, and its parameter list sits right in the class header:

  • Parameters marked var (or val) also become fields of the object, so there is nothing else to declare.

  • A class with no body needs no braces at all.

class Dog(var name: String, var age: Int)

Parameters become fields

Because the header says var name: String, the parameter and the field are the same thing: Scala stores the argument in the field name for you, so you never write this.name = name yourself.


Calling the constructor

val rex  = Dog("Rex", 4)
val luna = Dog("Luna", 7)

By the time these lines finish, rex.name is already "Rex", rex.age is 4, and the same for Luna.


The default constructor

If a class has no parameter list, Scala gives it a no-argument constructor — that's why Dog() worked in earlier lessons. The moment you add parameters to the header, that freebie disappears: from now on you must call Dog with the arguments you specified.


Your task

Declare the Dog class with a constructor that takes name: String and age: Int as var parameters. Then in mainFunction, create two dogs:

val rex  = Dog("Rex", 4)
val luna = Dog("Luna", 7)

Expected output:

Rex is 4
Luna is 7
STEP 1 OF 2
    Ctrl + Enter to check

    SCALA · FUNCTIONS & CLASSES

    Constructors in Scala, explained

    What a constructor does

    A constructor runs when an object is created, and sets up its initial state. Without one, you would create a Dog and then fill in its fields line by line:

    val dog = Dog()
    dog.name = "Rex"
    dog.age = 4
    

    That works, but it is easy to forget a line and leave an object half set up. A constructor with parameters fills in the fields at the moment the object is created.

    The primary constructor

    In Scala, a class's main constructor is part of the class header. The parameters go in parentheses right after the class name:

    class Dog(var name: String, var age: Int)
    

    This one line does a lot. It defines a constructor that takes a String and an Int, and because each parameter is marked with var, Scala also creates a field for it, readable and writable from outside. A class with no body needs no braces. Creating objects is then just a call with arguments:

    val rex = Dog("Rex", 4)
    val luna = Dog("Luna", 7)
    println(rex.name + " is " + rex.age)
    println(luna.name + " is " + luna.age)
    

    This prints:

    Rex is 4
    Luna is 7
    

    The fields are already set when Dog(...) returns. Because they are var fields, they can be changed afterwards: rex.age = 5 is valid.

    The modifier in front of a parameter decides what you get

    • var name: String creates a field that can be read and reassigned from outside.
    • val name: String creates a field that can be read but not reassigned. Writing rex.name = "y" is rejected with Reassignment to val name.
    • name: String, with neither, is only a parameter. The class body can use it, but it is not a field that outsiders can reach. Reading rex.name from outside fails with value name cannot be accessed as a member of Dog.

    This is why the lesson's class uses var on both parameters: the code in mainFunction reads rex.name and rex.age from outside the class.

    Calling the constructor

    The constructor needs all of its arguments. After class Dog(var name: String, var age: Int), a call with one argument doesn't compile. The compiler reports missing argument for parameter age. A call with no arguments fails in the same way, which means the free no-argument constructor of a class without a parameter list is gone as soon as you declare parameters.

    Parameters can have default values, which makes some of them optional:

    class Cat(val name: String, val age: Int = 1)
    
    val a = Cat("Tom")       // age is 1
    val b = Cat("Tom", 3)    // age is 3
    

    Code in the class body

    Statements written directly in the class body belong to the primary constructor and run each time an object is created:

    class Cat(val name: String) {
        println(s"Creating $name")
    }
    

    Calling Cat("Tom") prints Creating Tom.

    Auxiliary constructors

    A class can have extra constructors, declared with def this. They have no return type, and their first statement must call another constructor of the same class:

    class Dog(var name: String, var age: Int) {
        def this(name: String) = this(name, 0)
    }
    

    Here Dog("Rex") calls the one-argument constructor, which hands over to the primary one with age 0. A class with no primary parameters can also write def this(name: String, age: Int) = { this(); this.name = name; this.age = age } and assign fields in the body. That works, but the primary constructor is shorter and is the usual choice.

    The this keyword

    When a parameter has the same name as a field, the bare name refers to the parameter, because the closest definition wins. this stands for the current object, so this.name is the field. With a var in the primary constructor, you don't need this assignment at all, since Scala creates the field and fills it in for you.

    The exercise

    Declare Dog with a primary constructor taking name and age as var parameters, then create the two dogs in mainFunction:

    class Dog(var name: String, var age: Int)
    
    class Solution {
        def mainFunction(): Unit = {
            val rex = Dog("Rex", 4)
            val luna = Dog("Luna", 7)
            println(rex.name + " is " + rex.age)
            println(luna.name + " is " + luna.age)
        }
    }
    

    The output is the two lines Rex is 4 and Luna is 7.

    Key takeaways

    • The primary constructor's parameters sit in the class header.
    • var or val in front of a parameter makes it a field. Without either, it is only a parameter.
    • All arguments must be given, unless the parameter has a default value.
    • Extra constructors use def this and must start by calling another constructor.
    Keep going with ScalaAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free