4.1. Creating a Primary Constructor

Problem

You want to create a primary constructor for a class, and you quickly find that the approach is different than Java.

Solution

The primary constructor of a Scala class is a combination of:

  • The constructor parameters

  • Methods that are called in the body of the class

  • Statements and expressions that are executed in the body of the class

Fields declared in the body of a Scala class are handled in a manner similar to Java; they are assigned when the class is first instantiated.

The following class demonstrates constructor parameters, class fields, and statements in the body of a class:

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

  println("the constructor begins")

  // some class fields
  private val HOME = System.getProperty("user.home")
  var age = 0

  // some methods
  override def toString = s"$firstName $lastName is $age years old"
  def printHome { println(s"HOME = $HOME") }
  def printFullName { println(this) }  // uses toString

  printHome
  printFullName
  println("still in the constructor")

}

Because the methods in the body of the class are part of the constructor, when an instance of a Person class is created, you’ll see the output from the println statements at the beginning and end of the class declaration, along with the call to the printHome and printFullName methods near the bottom of the class:

scala> val p = new Person("Adam", "Meyer")
the constructor begins
HOME = /Users/Al
Adam Meyer is 0 years old
still in the constructor

Discussion

If you’re coming to Scala from Java, you’ll find that the process of declaring a primary constructor in Scala is quite different. In Java it’s fairly obvious when you’re in the main constructor and when you’re not, but Scala blurs this distinction. However, once you understand the approach, it also makes your class declarations more concise than Java class declarations.

In the example shown, the two constructor arguments firstName and lastName are defined as var fields, which means that they’re variable, or mutable; they can be changed after they’re initially set. Because the fields are mutable, Scala generates both accessor and mutator methods for them. As a result, given an instance p of type Person, you can change the values like this:

p.firstName = "Scott"
p.lastName = "Jones"

and you can access them like this:

println(p.firstName)
println(p.lastName)

Because the age field is declared as a var, it’s also visible, and can be mutated and accessed:

p.age = 30
println(p.age)

The field HOME is declared as a private val, which is like making it private and final in a Java class. As a result, it can’t be accessed directly by other objects, and its value can’t be changed.

When you call a method in the body of the class—such as the call near the bottom of the class to the printFullName method—that method call is also part of the constructor. You can verify this by compiling the code to a Person.class file with scalac, and then decompiling it back into Java source code with a tool like the JAD decompiler. After doing so, this is what the Person class constructor looks like:

public Person(String firstName, String lastName)
{
  super();
  this.firstName = firstName;
  this.lastName = lastName;
  Predef$.MODULE$.println("the constructor begins");
  age = 0;
  printHome();
  printFullName();
  Predef$.MODULE$.println("still in the constructor");
}

This clearly shows the printHome and printFullName methods call in the Person constructor, as well as the initial age being set.

When the code is decompiled, the constructor parameters and class fields appear like this:

private String firstName;
private String lastName;
private final String HOME = System.getProperty("user.home");
private int age;

Note

Anything defined within the body of the class other than method declarations is a part of the primary class constructor. Because auxiliary constructors must always call a previously defined constructor in the same class, auxiliary constructors will also execute the same code.

A comparison with Java

The following code shows the equivalent Java version of the Person class:

// java
public class Person {

  private String firstName;
  private String lastName;
  private final String HOME = System.getProperty("user.home");
  private int age;

  public Person(String firstName, String lastName) {
    super();
    this.firstName = firstName;
    this.lastName = lastName;
    System.out.println("the constructor begins");
    age = 0;
    printHome();
    printFullName();
    System.out.println("still in the constructor");
  }

  public String firstName() { return firstName; }
  public String lastName() { return lastName; }
  public int age() { return age; }

  public void firstName_$eq(String firstName) {
    this.firstName = firstName;
  }

  public void lastName_$eq(String lastName) {
    this.lastName = lastName;
  }

  public void age_$eq(int age) {
    this.age = age;
  }

  public String toString() {
    return firstName + " " + lastName + " is " + age + " years old";
  }

  public void printHome() {
    System.out.println(HOME);
  }

  public void printFullName() {
    System.out.println(this);
  }

}

As you can see, this is quite a bit lengthier than the equivalent Scala code. With constructors, I find that Java code is more verbose, but obvious; you don’t have to reason much about what the compiler is doing for you.

Those _$eq methods

The names of the mutator methods that are generated may look a little unusual:

public void firstName_$eq(String firstName) { ...
public void age_$eq(int age) { ...

These names are part of the Scala syntactic sugar for mutating var fields, and not anything you normally have to think about. For instance, the following Person class has a var field named name:

class Person {
  var name = ""
  override def toString = s"name = $name"
}

Because name is a var field, Scala generates accessor and mutator methods for it. What you don’t normally see is that when the code is compiled, the mutator method is named name_$eq. You don’t see that because with Scala’s syntactic sugar, you mutate the field like this:

p.name = "Ron Artest"

However, behind the scenes, Scala converts that line of code into this code:

p.name_$eq("Ron Artest")

To demonstrate this, you can run the following object that calls the mutator method in both ways (not something that’s normally done):

object Test extends App {

  val p = new Person

  // the 'normal' mutator approach
  p.name = "Ron Artest"
  println(p)

  // the 'hidden' mutator method
  p.name_$eq("Metta World Peace")
  println(p)

}

When this code is run, it prints this output:

name = Ron Artest
name = Metta World Peace

Again, there’s no reason to call the name_$eq method in the real world, but when you get into overriding mutator methods, it’s helpful to understand how this translation process works.

Summary

As shown with the equivalent Scala and Java classes, the Java code is verbose, but it’s also straightforward. The Scala code is more concise, but you have to look at the constructor parameters to understand whether getters and setters are being generated for you, and you have to know that any method that’s called in the body of the class is really being called from the primary constructor. This was a little confusing when I first started working with Scala, but it quickly became second nature.

Get Scala Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.