Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin Property: "Type parameter of a property must be used in its receiver type"

I have the following simple Kotlin extension functions:

// Get the views of ViewGroup
inline val ViewGroup.views: List<View>
    get() = (0..childCount - 1).map { getChildAt(it) }

// Get the views of ViewGroup of given type
inline fun <reified T : View> ViewGroup.getViewsOfType() : List<T> {
    return this.views.filterIsInstance<T>()
}

This code compiles and works fine. But, I want the function getViewsOfType to be a property, just like the views. Android Studio even suggests it. I let AS do the refactoring and it generates this code:

inline val <reified T : View> ViewGroup.viewsOfType: List<T>
    get() = this.views.filterIsInstance<T>()

But this code doesn't compile. It causes error: "Type parameter of a property must be used in its receiver type"

What is the issue here? Searching for help on this error doesn't seem to lead to an answer.

like image 287
Greg Ennis Avatar asked May 25 '17 13:05

Greg Ennis


People also ask

What is type parameter in Kotlin?

The type parameter lets you specify exactly that—instead of “This variable holds a list,” you can say something like “This variable holds a list of strings.” Kotlin's syntax for saying “a list of strings” looks the same as in Java: List<String> . You can also declare multiple type parameters for a class.

What is out type in Kotlin?

"Out" keyword is extensively used in Kotlin generics. Its signature looks like this − List<out T> When a type parameter T of a class C is declared out, then C can safely be a super type of C<Derived>. That means, a Number type List can contain double, integer type list.


1 Answers

The error means that you can only have a generic type parameter for an extension property if you're using said type in the receiver type - the type that you're extending.

For example, you could have an extension that extends T:

val <T: View> T.propName: Unit
    get() = Unit

Or one that extends a type that uses T as a parameter:

val <T: View> List<T>.propName: Unit
    get() = Unit

As for why this is, I think the reason is that a property can't have a generic type parameter like a function can. While we can call a function with a generic type parameter...

val buttons = viewGroup.getViewsOfType<Button>()

... I don't believe a similar syntax exists for properties:

val buttons = viewGroup.viewsOfType<Button> // ??
like image 129
zsmb13 Avatar answered Oct 10 '22 02:10

zsmb13