Automatically Promoting Constructor Parameters to Fields
When writing object-oriented code, you frequently want a constructor that takes in values and assigns them to object fields. Take the the following constructor, which is from LibGDX’s Stage class.
public class Stage {
private Viewport viewport;
private final Batch batch;
// ..
public Stage (Viewport viewport, Batch batch) {
if (viewport == null)
throw new IllegalArgumentException("viewport cannot be null.");
if (batch == null)
throw new IllegalArgumentException("batch cannot be null.");
this.viewport = viewport;
this.batch = batch;
// ...
}
}
The first two statements check that the arguments are non-null. This could be avoided in languages like Scala or Kotlin that have non-nullable types. However, I want to focus on the third and fourth statements, where the constructor values are assigned to fields in the object. This pattern is annoying to write and maintain. You effectively have to write every variable name four times - once in the declaration, another time in the constructor arguments, and two more times in the assignment statements. Anytime something changes about the local variables, it must be updated in three different spots in the code.
This kind of code is also highly vulnerable to copy-paste errors, and I can think of several instances where I’ve made a mistake such as the one below:
public Point2D (float x, float y) {
this.x = x;
this.y = x; // Whoops!
}
Finally, this repetition makes data classes (classes that simply hold data) very cumbersome to write.
Thankfully, some languages have solved this problem by letting you specially mark certain constructor arguments. These arguments are then “promoted” to fields, and automatically assigned from the constructor argument. These are some of the languages that implement this quality of life improvement:
Coffeescript
Coffeescript lets you use the @
symbol to mark a constructor parameter so that it will be automatically assigned to a local variable. This syntax makes a lot of sense, since the @
prefix, when used in the body of a method, accesses local variables.
# From https://arcturo.github.io/library/coffeescript/03_classes.html
class Animal
constructor: (@name) ->
Hack
Hack, a statically typed dialect of PHP, promotes constructor parameters to local fields when you add a visibility modifier.
// From https://docs.hhvm.com/hack/other-features/constructor-parameter-promotion
class User {
public function __construct(private int $id,
private string $name,
private bool $preferred) {
// ...
}
}
Scala
Scala goes one step further by unifying the constructor and the class definition. This results in a really concise way of declaring data classes.
// From http://docs.scala-lang.org/tutorials/tour/classes.html
class Point(var x: Int, var y: Int) {
}
Kotlin
Kotlin follows Scala’s same pattern where the constructor and class definition are unified.
// From https://kotlinlang.org/docs/reference/classes.html
class Person(val firstName: String, val lastName: String, var age: Int) {
}