Why does Kotlin have two types of constructors?

2.6k views Asked by At

Kotlin has two types of constructors, primary and secondary. What is the purpose of having two types? In my opinion it makes the code more complicated and inconsistent. If both types of constructors create objects of a class, they are equally important to a class.

Meanwhile, multiple initialisers also introduce confusion and reduce readability.

3

There are 3 answers

1
Pawel On

Primary constructor can define what parameters are passed into the init blocks. For example:

class Foo(a: Bar){
    val b : Bar

    init { 
         b = a // value of "a" is known from primary constructor
    }

    constructor(a: Boo) : this(a.toBar())
}

Without explicit primary constructor call it would be impossible to determine what value/type of a should be used in init.

Primary constructor and initializer blocks always execute before secondary constructor block (doc).

1
hotkey On

Primary constructors cover the poplular use case when you need to save the values passed as the constructor arguments to the properties of the instance.

Basically, a primary constructor provides a shorthand for both declaring a property and initializing it from the constructor parameter.

Note that you can do the same without primary constructors at all:

class Foo {
    val bar: Bar

    constructor(barValue: Bar) {
        bar = barValue
    }
}

But, since this happens really often in the codebases, Kotlin primary constructors serve the purpose of reducing the boilerplate here:

class Foo(val bar: Bar)

Secondary constructors may complement or replace the primary one in order to support several construction routines for a single class.

1
Manushin Igor On

Philosophy: the main purpose - kotlin is pragmatic language. The main idea of it: exclude the most frequent boilerplate.

A lot of classes, which are used in the C#/Java have only one constructor with the following semantic:

  • Part of parameters are stored into the fields (with the same names)
  • Part of parameters are used by constructor to create other field (or extra validation)

Moreover, a lot of secondary constructors are used to call the primary constructor with default values (please see this question for C# language)

Therefore: to have simplified code (which reflects essence) you have to have ability to:

  • Support constructor parameters, which will be stored into the fields automatically (without this.myData = myData)
  • Support ability to create field from constructor parameters

Both of items above required, therefore all constructors have the same input values (because all fields should be initialized, however they are set out of constructor body). Therefore you have to have primary constructor, which will do initialization.

After this logic applying we get major rule: to cover the most frequent class initializing scenarios you have to have primary constructor with ability to define default parameter values. Additionally you should have ability to create secondary constructors to cover all other scenarios.

So, I repeat the main idea: primary constructor is needed to cover the most frequent cases (pragmatic purpose)