cershif
cershif

Reputation: 154

Kotlin Initialize Variable Inside Function in Constructor

In Kotlin variables not declared as nullable or lateinit must be initialized in the constructor (or init). I am trying to do this like this:

class Foo{
    var foo:myType
    init{
        complicatedFooInit()
    }

    fun complicatedFooInit(){
         foo = //a whole bunch of code here
    }

}

I still get the Property must be initialized or declared abstract error. You can easily reproduce this by making myType an Int and just setting it equal to 3 in the complicatedFooInit function. Obviously there are ways around this (just not making it a function, having complicatedFooInit return myType and setting foo equal to it, etc.). My question is, why is the above code invalid? Or is it valid with some tweaking?

Upvotes: 0

Views: 3254

Answers (2)

Alexey Romanov
Alexey Romanov

Reputation: 170723

Consider also that you can have multiple init blocks, so if you want to extract some part of initialization into a function, e.g.

init {
    complicatedFooInit()
    complicatedBarInit()
}

I would replace each function by a separate init block:

// comment about foo initialization
init {
    // body of complicatedFooInit()
}

// comment about bar initialization
init {
    // body of complicatedBarInit()
}

The problem is that you can't pass arguments to init blocks; but any arguments you'd pass to complicatedFooInit can only depend on the primary constructor parameters, and so can be set up in the beginning of the corresponding init block.

You also can't call the same function twice with different parameters,

init {
    complicatedFooInit(true)
    complicatedFooInit(false)
}

but you wouldn't want to anyway, because it would initialize foo twice; unless complicatedFooInit initializes different variables depending on its arguments, but it would make the compiler's burden mentioned in Михаил Нафталь's answer much worse!

Upvotes: 2

Compiler have no idea what's going on inside complicatedFooInit() function (cause it may be too burden to investigate all execution flow of potentially dozens nested functions called from init block). He wants to see initialization directly inside init block. So you need to make complicatedFooInit() return desired value:

class Foo {
    var foo: myType

    init {
        foo = complicatedFooInit()
    }

    fun complicatedFooInit(): myType {
        //a whole bunch of code here
       return ...
    }
}

Actually, in this case property initialization on declaration site will be more concise (no need for init block at all):

var foo: String = complicatedFooInit()

Upvotes: 5

Related Questions