What is the class constructor?

A class constructor is used to build an object from a class definition (wiki). In this post, we will discuss and compare the constructor in Kotlin with the language features of C++. As an example, we will use a simple point class. Our example class holds x and y coordinates as integer values.

Summary

In Kotlin, the constructor of a class can be broken down into 3 parts: primary constructor [1], initializer block [2], and secondary constructor(s) [3]. All parts are optional. The primary constructor and initializer function will be auto-generated in case they are not defined. The primary constructor is a part of the class header, and it goes after the class name and optional type parameters.

Kotlin constructor

Default / Primary Constructor

In every OOP language, a specific subroutine is used to create and prepare new objects. Every class in Kotlin can have one primary constructor. The “constructor” keyword can be omitted if no other modifiers are used.

Autogenerated

If no constructor or initializer block is explicitly defined, the compiler will automatically generate one. In the following code, the point class has its member variables initialized to 0. This is actually the same behavior in Kotlin and in C++.

class Point() {
    var x = 0
    var y = 0
}

or even


class Point {
    var x = 0
    var y = 0
}
class Point {
public:
    int x = 0;
    int y = 0;
};

In the following code the member variables of the point class, must be assigned during object construction.

class Point(
    var x: Int, 
    var y: Int)
class Point {
public:
    Point(int x, int y) :
        x(x), y(y)
    {
        
    }
    
    int x = 0;
    int y = 0;
};

Initializer block

The initializer block (short form is init) is executed even though the constructor is auto-generated. The following code will print “Init” for every new object. There can be any number of initializer blocks. They will be executed in the order they appear in the code.

class Point(
    var x: Int,
    var y: Int)
{
    init {
        doSomething()
    }
    
    private fun doSomething() {
        
    }
}
class Point {
public:
    Point(int x, int y) :
        x(x), y(y)
    {
        doSomething();
    }
    
    int x = 0;
    int y = 0;
    
private:
    void doSomething() {
        
    }
};

It is important to know, that the initializer block is executed even though the primary constructor is not specified. The call will happen before the body of the secondary constructer is run. There can be more than 1 init block. They will be run in the order they appear in the code.

class Point {
    var x = 0
    var y = 0

    init {
        println("init 1")
    }

    constructor(){
        println("secondary")
    }

    init {
        println("init 2")
    }
}

// prints:
// init 1
// init 2
// secondary

So what is the difference between the primary constructor and the init? The primary constructor can not have a code body. The init block is therefore a helper.

Default values / default parameters

In Kotlin you can give default values for any constructor argument. It is not important at which location the first default argument is placed.

class Point(var x: Int = 1, var y: Int) {
    
}
// does not compile
class Point {
public:
    Point(int x = 1, int y) :
        x(x), y(y)
    {
        
    }
    
    int x = 0;
    int y = 0;
};

Secondary Constructor / Constructor Overloading

In the last examples, we have shown how to create an object in a single way. But how do you overload a constructor in Kotlin? How do you create a secondary constructor?

If the class has a primary constructor, each secondary constructor needs to delegate to the primary constructor, either directly or indirectly through another secondary constructor(s).

class Point(
    var x: Int,
    var y: Int)
{
    init {
        doSomething()
    }

    constructor(vec: Point, origin: Point) : this(origin.x + vec.x, origin.y + vec.y) {

    }

    private fun doSomething() {
    
    }
}

class Point(
    var x: Int = 0,
    var y: Int = 0)
{
    init {
        doSomething()
    }

    constructor(vec: Point, origin: Point) : this() {
        x = origin.x + vec.x
        y = origin.y + vec.y
        doSomething()
    }

    private fun doSomething() {
        
    }
}
class Point {
public:
    Point(int x, int y) :
        x(x), y(y)
    {
        doSomething();
    }
    
    Point(const Point &vec, const Point &origin) {
        x = origin.x + vec.x;
        y = origin.x + vec.y;
        doSomething();
    }
    
    int x = 0;
    int y = 0;
    
private:
    void doSomething() {
        
    }
};

If you don’t call a primary constructor you will get the error “Primary constructor call expected”.

As you can see in some cases the doSomething method is executed several times during object creation. You have to take care to create a clean code structure to avoid that. One possibility is to use a static factory method instead.

Factory Method

When using the design pattern Factory Method, we can delegate object creation to a single (primary) constructor. The logic to set up the object is within a static accessible function. One advantage is that we can use better naming. In the following code example, a point can be created from a vector and another point. The factory method calculates the x and y coordinates and passes them to the primary constructor.

More details can be found in Factory Method.

class Point(
    var x: Int = 0,
    var y: Int = 0)
{
    companion object {
        fun fromVector(vec : Point, origin: Point) : Point {
            val x = origin.x + vec.x
            val y = origin.y + vec.y
            return Point(x, y)
        }
    }
    init {
        doSomething()
    }
    
    private fun doSomething() {

    }
}
class Point {
public:
    Point(int x, int y) :
        x(x), y(y)
    {
        doSomething();
    }
    
    static Point fromVector(const Point &vec, const Point &origin) {
        int x = origin.x + vec.x;
        int y = origin.y + vec.y;
        return Point(x, y);
    }
    
    int x = 0;
    int y = 0;
    
private:
    void doSomething() {
        
    }
};

Private / Protected Constructor

The rules for visibility are the same in Kotlin as in C++. However, the default behavior in Kotlin is public, while in C++ it is private (for classes). We can create primary and secondary constructors in public, protected, and private visibility.

Public primary constructor. The object can be created by clients and subclassed.

class Point public constructor(){
    var x = 0
    var y = 0
}

// same as:
class Point (){
    var x = 0
    var y = 0
}
class Point {
public:
    
    Point() {

    }

    int x = 0;
    int y = 0;
};

Protected primary constructor. The object cannot be created by clients, but subclassed. To be able to create an object by clients the point class needs at least one public / protected (secondary) constructor.

open class Point protected constructor(){
    var x = 0
    var y = 0
}

class DerivedPoint : Point() {
    
}

fun main() {
    var p = Point() // does not compile
    var p2 = DerivedPoint()
}
class Point {
public:
    int x = 0;
    int y = 0;
    
protected:
    Point() {

    }
};

class DerivedPoint: public Point {

};

Private primary constructor. The object can not be created by clients and neither be subclassed. To be able to create a subclass the point class it will need at least one public or protected (secondary) constructor.


open class Point private constructor(){
    var x = 0
    var y = 0
}

class DerivedPoint : Point() { // does not compile

}

class Point {
public:
    

    int x = 0;
    int y = 0;
    
private:
    Point() {

    }
};

class DerivedPoint: public Point {

};

Singleton

One example to use a protected / private constructor is to implement the Singleton design pattern. Read more in Singleton.

class Point private constructor(){

    var x = 0
    var y = 0

    companion object {
        val instance = Point()
    }
}

Or even by using directly a static object.

object Point {
    var x = 0
    var y = 0    
}
class Point {
public:


    int x = 0;
    int y = 0;
    
    static Point & instance() {
        static Point p;
        return p;
    }
    
private:    
    Point() {

    }
};

Copy Constructor

In C++ it is common to declare as well a copy constructor. This constructor is called whenever an object is newly created and directly assigned by another one. The following code demonstrates that.

auto obj1; // default constructor
auto obj2 = obj1; // copy constructor

In Kotlin things are a bit different. First of all, Kotlin is working with pointers / references. The pointers will have a reference count. To demonstrate the behavior we will use the std::shared_ptr from the standard library.

var obj1 = AnyClass()
var obj2 = obj1;
auto obj1 = std::make_shared<AnyClass>();
auto obj2 = obj1;

If you use a data class, there will be the copy function that can be called to actually copy an object. For all other cases, you must implement a solution for yourself. To do that be careful, because every (member) variable behaves like a shared_ptr.

In order to actually copy an object, you have to implement your own solution.

class Point : Cloneable {
    var x = 0
    var y = 0

    public override fun clone(): Any {
        val newPoint = Point()
        newPoint.x = this.x
        newPoint.y = this.y
        return newPoint
    }
}

fun main() {
    var p = Point()
    var p2 = p.clone();
}

Data class constructor

Most of the things apply as well to a data class constructor. However, some exceptions apply.

1. In Kotlin a default constructor for a data class is not possible. The following code will not compile. As an equivalent in C++, we use a struct. Usually, structures are used in C++ for pure structures (no member functions), even so, the difference of structures and classes is very subtle in C++.

// does not compile
data class Point() {
    
}
struct Point {
    
};

2. In the constructor only val or var are allowed. This means every constructor parameter must be a part of the data class.

// does not compile
data class Point(var x: Int, y: Int) {

}
struct Point {
    Point(int x, int y) :
        x(x)
    {
        
    }
    int x = 0;
};

Inheritance

When using inheritance and derived classes, Kotlin behaves like C++. In case a default constructor is available it is directly called. It must be however explicitly called in the derived class.

open class Point {
    var x = 0
    var y = 0
}

class DerivedPoint : Point() {
    
}
class Point {
public:
    int x = 0;
    int y = 0;
};

class DerivedPoint: public Point {
    
};

The derived class must call one constructor which is available. In the following example the primary constructor has parameters, while the secondary constructor has not. The derived class calls the secondary constructor of parent class.

open class Point(var x: Int, var y: Int) {
    constructor() : this(0, 0) {
        
    }
}

class DerivedPoint : Point() {
    
}
class Point {
public:
    Point(int x, int y) :
        x(x), y(y)
    {
        
    }
    
    Point() {
        
    }
    
    int x = 0;
    int y = 0;
};

class DerivedPoint: public Point {
    
};

First, the whole parent (super) is constructed (including all init blocks), then the child is built. The order of execution is as already described above.

open class Point(var x: Int, var y: Int) {
    constructor() : this(0, 0) {
        println("secondary constructor parent")
    }

    init {
        println("init parent")
    }
}

class DerivedPoint : Point() {
    init {
        println("init child")
    }
}

// prints:
// init parent
// secondary constructor parent
// init child