Introduction

Scala constructors can behave differently from Java ones. The most visible difference is the way you can declare the so-called primary constructor directly in the class declaration as you will shortly see.

The primary constructor

In Scala a class can have as many constructors as wanted but there is only one primary constructor. There is a default one generated by the compiler if you don’t provide any argument to the class definition, for example :

class Person {
  var firstName : String = _
  var lastName  : String = _
}

In this case a default no-arg constructor will be created, as you can see in the output provided by javap:

public class Person {
  // ...
  public Person();
}

Primary constructor within class definition

There is a concise way to declare a primary constructor, it consists of declaring it within the class definition, like this :

class Person(val firstName: String, val lastName: String) {}

That’s it ! In one line you’ve defined a class named Person which have two attributes, both of type String, and a primary constructor which is now the mandatory entry point to this class, as you can see :

public class Person {
  public java.lang.String firstName();
  public java.lang.String lastName();
  public Person(java.lang.String, java.lang.String);
}

If you pay attention to the generated code above you will see that there’s only one constructor, the default no-arg one isn’t there anymore, so the public Person(java.lang.String, java.lang.String); constructor is now the only way to create an instance of Person.

But there is more : as you can see the compiler automatically generated two getters, but no setters. That’s because we told the two attributes were vals, not vars. Let’s see what happens when we change val by var :

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

The generated code is now :

public class Person {
  public java.lang.String firstName();
  public void firstName_$eq(java.lang.String);
  public java.lang.String lastName();
  public void lastName_$eq(java.lang.String);
  public Person(java.lang.String, java.lang.String);
}

Since the attributes are now mutable the compiler automatically generated the setters for us, saving us from typing them (or telling our IDE to do so).

It is to be noted that these are not getters/setters in the JavaBean sense, the methods aren’t called getXXX() and setXXX(). More on that in another post.

Using access modifiers

You can also use some modifier in order to change the generated code produced by the compiler. For example if you prepend private to a parameter,

class Person(private var firstName: String, val lastName: String) {}

here’s what happen :

public class Person {
  private java.lang.String firstName;
  private final java.lang.String lastName;
  private java.lang.String firstName();
  private void firstName_$eq(java.lang.String);
  public java.lang.String lastName();
  public Person(java.lang.String, java.lang.String);
}

Both getter (firstName()) and setter (firstName_$eq(java.lang.String)) are now private and thus can only be called from within an instance.

Statements in class definition

The primary constructor executes all statements in the class definition. For example :

class Person(val firstName: String, val lastName: String) {
  println("Initializing object ...")
}

should display

scala> :load src/Person.scala
Loading src/Person.scala...
defined class Person

scala> val p = new Person("John", "Doe")
Initializing object ...
p: Person = Person@60e31054

Since the primary constructor is always called first, all statements in the class definition will be executed first.

The auxiliary constructors

These constructors are more similar to their Java counterpart. One big difference though : they aren’t named after the class’s name but they follow a schema used by other languages such as Python or Ruby. In this case they are named this().

class Person {
  var firstName : String = _
  var lastName  : String = _

  def this(firstName: String) {
    this()
    this.firstName = firstName
  }

  def this(firstName: String, lastName: String) {
    this(firstName)
    this.lastName = lastName
  }
}

The corresponding java code produced looks like this :

public class Person {
  // ...
  public Person();
  public Person(java.lang.String);
  public Person(java.lang.String, java.lang.String);
}

The first line of code within an auxiliary constructor has to call either another auxiliary constructor or the primary one. This ensures that the object is going through the whole process of initialization.

Parameter default values

Often you can get rid of the auxiliary constructors by using default values for parameter inside the primary constructor :

class Person(var firstName: String = null, var lastName: String = null) {}
// ...
val p = new Person()

I’m not fond of this way of initializing an object though.

Last words

As usual, if you have any remarks, please feel free to share them.