3

Following code report property must be initialized or be abstract error.

// MyApi.kt
interface MyApi {

    ...
}

// MyFetch.kt
class MyFetch {

    private val myApi: MyApi  // <- this line

    ...
}

It can use lateinit statement in mutable variable, but how should I predefined in val?

ccd
  • 5,788
  • 10
  • 46
  • 96

3 Answers3

1

You can use lazy, or make it nullable

private val myApi: MyApi? = null
1

You actually have to initialize the variable on the time of object creation in the variable declairation itself or in the init{} block, since there is no preinit null type in the Kotlin.

And since your variable is val not var you cannot set it after created so there's no point of creating the variable.

If you meant to initialize the variable later on but only once, check this answer: https://stackoverflow.com/a/48445081/11377112 This is done by delegation like this:

class InitOnceProperty<T> : ReadWriteProperty<Any, T> {

    private object EMPTY

    private var value: Any? = EMPTY

    override fun getValue(thisRef: Any, property: KProperty<*>): T {
        if (value == EMPTY) {
            throw IllegalStateException("Value isn't initialized")
        } else {
            return value as T
        }
    }

    override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
        if (this.value != EMPTY) {
            throw IllegalStateException("Value is initialized")
        }
        this.value = value
    }
}

Now you can delegate the variable by the delegate

var property: Int by InitOnceProperty()
Animesh Sahu
  • 7,445
  • 2
  • 21
  • 49
1

The Separation of Concerns design pattern would favor passing a value to the constructor. So some other class that instantiates your MyFetch class would also instantiate your MyApi instance and pass it to the constructor:

class MyClass(val myApi: MyApi){

}

//Some higher level class:
val myAPI = object: MyApi { //... }
val myClass = MyClass(myApi)

But you can also just initialize it from within the class. This would make sense if MyApi is tightly coupled to the behavior of MyClass:

class MyClass {

    val myApi = object: MyApi { //... }

}

// or

class MyClass {

    val myApi: MyApi

    init {
        myApi = object: MyApi { //... }
    }
}

In any of the three cases, a value of read-only val property has to be assigned in either the constructor, inline with the declaration, or in an init block. The only other option is to use a property delegate.

Tenfour04
  • 83,111
  • 11
  • 94
  • 154