ReadOnlyProperty - type arguments automatically inferred not validating bounds

Viewed 21

I'm trying to inject value into class property using by keyword.
No problem implementing the code below.

open class Component
class ComponentA: Component()

class Equipment(val components: List<Component>) {

    inline fun <reified T> getComponent(): T? {
        return components.firstOrNull { it is T } as T?
    }

    val ca: ComponentA by find<ComponentA>()  //this is what I intend to do
    val ca1: List<ComponentA> by find()       //no error or warning
    val ca2 by find<List<ComponentA>>()       //Error: Type argument is not within its bounds
}

inline fun <reified T> find(): ReadOnlyProperty<Equipment, T> where T : Component {
    return ReadOnlyProperty { ref, _ -> ref.getComponent<T>() ?: throw Exception("Not found") }
}

But I find it is weird that the val ca1: List<ComponentA> by find() not showing any error or warning. Error still show normally when I try val ca2 by find<List<ComponentA>>().
Can anybody explain why this happened and how to make sure ca1 definition syntax is invalid.

I'm using:

  • AdoptOpenJDK 11.0.7.10 hotspot
  • Kotlin 1.6.21
  • IntelliJ IDEA 2021.3.2
1 Answers

well I think the problem is from IDEA with the compiler, I tried using android functions like viewModels() with List instead of ViewModel and I had the same problem, the IDEA will not show any error:

enter image description here

but when you compile the code you will get an error:

enter image description here

so you can ignore this, it's just a problem with the IDEA, also you have some mistakes in your code,

val components: List<Equipment> this should be val components: List< Component >

return components.firstOrNull { it is T } as T and this should be return components.firstOrNull { it is T } as T? because you cannot cast a null type to a non-null type

so your code should look like this:

open class Component
class ComponentA: Component()

class Equipment(val components: List<Component>) {

    inline fun <reified T> getComponent(): T? {
        return components.firstOrNull { it is T } as T?
    }

    val ca: ComponentA by find<ComponentA>()  //this is what I intend to do
    // val ca1: List<ComponentA> by find()       //no error or warning
    // val ca2 by find<List<ComponentA>>()       //Error: Type argument is not within its bounds
}

inline fun <reified T> find(): ReadOnlyProperty<Equipment, T> where T : Component {
    return ReadOnlyProperty { ref, _ -> ref.getComponent<T>() ?: throw Exception("Not found") }
}
Related