Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the Kotlin class initialisation semantics?

I haven't been able to find anything in the language definition that explains the initialisation of a class in Kotlin.

import java.util.Properties

fun main(args: Array<String>) {
    val out = MyClass()
    out.fn()
}

class MyClass {
    private val a = Properties() // 1

    init {
        fn()
    }

    public fun fn() {
        println("Fn called.  a = $a")
    }

    //  private val a = Properties() // 2
}

The results of running this program change depending whether the property is initialised at (1) or at (2).

I'm surprised that the declaration order is relevant in the language and would like to understand the decisions behind this. My expectation would be that properties are initialised before the constructor body is invoked.

like image 272
Nigel Eke Avatar asked Nov 13 '15 08:11

Nigel Eke


2 Answers

My expectation would be that properties are initialised before the constructor body is invoked.

Well, init block is not a constructor. It is a different construct which allows you to perform the initialization of the object and they [init blocks] are performed in the declaration order with the property initializers.

Constructors are a different beast ant they are performed after all the properties were initialized and all init blocks were performed. Look at the following example:

class A(val value: Int) {
    constructor(): this(0) {        
        println("Constructor")
    }    

    init {
        println("Init block")
    }
}

fun main(args: Array<String>) {
    val a = A()
}

Output is:

Init block  
Constructor

You can place the init block wherever you want: before the constructor or after it; it will always be performed before the A's constructor (secondary constructor, in this example).

like image 173
aga Avatar answered Oct 29 '22 08:10

aga


Simply put: when an instance of a class is created, (almost) firstly runs the constructor of the parent class (if present), then the primary constructor.

The primary constructor executes code declared in the class body from the top to the bottom. Also the names became available by the same rule:

class Foo(a: String = "might be first"
          val b: String = "second" + a) : Boo(a + b + "third"){
    var c = a + "fourth" + b

    init {print("fifth: $c")}

    val d = "sixth"
    init {print("seventh: the end of the primary constructor"}
}

If you invoke a secondary constructor, then it works after the primary one as it is composed in the chain (similar to invoking the parent constructors).

like image 24
voddan Avatar answered Oct 29 '22 08:10

voddan