0

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?

2 Answers 2

5

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()
Sign up to request clarification or add additional context in comments.

2 Comments

Yes, I am aware of this workaround, as mentioned. Fair point about the burden allowing this would place on the compiler, though it clearly seems achievable.
Maybe achievable, but you have to consider that fast compile times are a major requirement.
2

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!

1 Comment

I believe you can pass arguments to init - the primary constructor parameters, so it is technically possible (though likely bad practice) to call the Init function with two different parameters. I believe the compiler burden is the ultimate reason you can't do what I want.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.