21

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.

Greg Ennis
  • 14,917
  • 2
  • 69
  • 74

1 Answers1

20

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> // ??
zsmb13
  • 85,752
  • 11
  • 221
  • 226
  • Yeah I think this is right. In fact when thinking about it this way, my `getViewOfType` function is kind of useless since Kotlin already has a way to filter collection by type. – Greg Ennis May 25 '17 at 13:55