Classes: Constructors

Scala gives you a number of ways to model the world around you, and a basic way that’s found in every OOP language is the class. As with other OOP languages, a Scala class is a template or blueprint for:

  • Creating objects (instances of classes) that have a particular data structure
  • Providing initial values for its internal state (in its constructor)
  • Providing behaviors through member methods

The class constructor

When you model things around you, such as a person, you’ll find that everything you model has attributes. For example, a person has a name, age, height, weight, gender, and other attributes.

When you define a class you typically specify the most important of these attributes as constructor parameters. For example, in the physical world a person has at least a first and last name, and these are both required, so we declare those parameters in the constructor:

class Person(var firstName: String, var lastName: String)

When a class starts having many constructor parameters I write it on multiple lines, like this:

class Person(
    var firstName: String,
    var lastName: String

With either of those styles, in Scala 3 you create a new instance of a Person like this:

val john = Person("John", "Doe")
val mary = Person("Mary", "Doe")

This is what I mean by a blueprint or template: you can literally create trillions of unique instances of a class from the blueprint. Each active instance, such as john or mary, is then considered a running object.

Accessing the constructor parameters

Here’s another instance of a Person:

val p = Person("Reginald", "Dwight")

Given that instance, you can access its two constructor parameter fields like this:

println(p.firstName)   // prints "Reginald"
println(p.lastName)    // prints "Dwight"

Because I declared both of the parameters as var fields, you can also modify them:

p.firstName = "Elton"
p.lastName = "John"

When you print those fields again, you’ll see that they have the new values:

println(p.firstName)   // prints "Elton"
println(p.lastName)    // prints "John"

Defining constructor parameters as var fields is common in the OOP style.

var vs val

You can also declare those two fields as val parameters instead:

class Person(
    val firstName: String,
    val lastName: String

When you use val for the fields they are read-only — meaning that you can access them but not update them — as shown here:

// create a new Person
val p = Person("Reginald", "Dwight")

// print the fields
println(p.firstName)    // prints "Reginald"
println(p.lastName)     // prints "Dwight"

// errors
p.firstName = "Elton"   // ERROR: Reassignment to val firstName
p.lastName = "John"     // ERROR: Reassignment to val lastName

In the real world the way programmers define class parameters goes like this:

  • When programming in an OOP style, fields are typically mutable, so constructor parameters are declared as var
  • When programming in an FP style, fields are always immutable, so constructor parameters are declared as val

Because this book doesn’t get deep into FP, we’ll define most fields as var so they can be mutated (update).

You’ll almost always want to define constructor parameters as either val or var. Technically you can define parameters without the val or var keywords, but as a practical matter I don’t usually do that.


Note: This text comes from my book, Learn Scala 3 The Fast Way!