Considering this code is it possible to filter a l...
# getting-started
i
Considering this code is it possible to filter a list using reified type
.customFilterReified<AdvancedInterface>()
and return a list of
Advanced
objects instead of
BaseInterface
objects (heaving same behaviour as filtering using
KClass
.customFilterWithKClass(AdvancedInterface::class)
) ? 🤔
Copy code
interface BaseInterface
interface AdvancedInterface

class Advanced : BaseInterface, AdvancedInterface {
    val someProperty = "someProperty"
}

// 1 FILTER USING KCLASS - OK
fun <T : BaseInterface> List<T>.customFilterWithKClass(item: KClass<*>): List<T> = filter { item.isInstance(it) }

// 2 FILTER USING REIFIED - PROBLEM
inline fun <reified T> List<BaseInterface>.customFilterReified(): List<BaseInterface> = filter { it is T }

// USAGE
fun main() {
    val items = listOf(Advanced())

    // 1 FILTER USING KCLASS - OK
    items // List<Advanced>
        .customFilterWithKClass(AdvancedInterface::class) // returns List<Advanced> - OK
        .map { it.someProperty } //

    // 2 FILTER USING REIFIED - PROBLEM
    items // List<Advanced>
        .customFilterReified<AdvancedInterface>() // returns List<BaseInterface> - PROBLEM
        .map { it.someProperty } // ERROR: Unresolved reference: someProperty
}
w
You forgot to actually use your reified generic argument in your function signature. If you would write:
Copy code
inline fun <reified T> List<BaseInterface>.customFilterReified(): List<T /* Not BaseInterface */> = …
I’m quite sure that what you want is
items.filterIsInstance<AdvancedInterface>()
Also, if you use `.mapNotNull { it as? T }`you wouldn’t need an unsafe cast
i
Good catch. I have updated the code a bit using you suggestions, however the
customFilterReified
gives me
AdvancedInterface
type rather than
Advanced
type. Is there a way to get the oriiginal receiver type within the extension (
Advanced
) 🤔
Copy code
interface BaseInterface
interface AdvancedInterface

class Advanced : BaseInterface, AdvancedInterface {
    val someProperty = "someProperty"
}

// 1 FILTER USING KCLASS - OK
fun <T : BaseInterface> List<T>.customFilterWithKClass(item: KClass<*>): List<T> = filter { item.isInstance(it) }

// 2 FILTER USING REIFIED - PROBLEM
inline fun <reified T> List<BaseInterface>.customFilterReified(): List<T> = filterIsInstance<T>()

// USAGE
fun main() {
    val items = listOf(Advanced())

    // 1 FILTER USING KCLASS - OK
    items // List<Advanced>
        .customFilterWithKClass(AdvancedInterface::class) // returns List<Advanced> - OK
        .map { it.someProperty } //

    // 2 FILTER USING REIFIED - PROBLEM
    items // List<Advanced>
        .customFilterReified<AdvancedInterface>() // returns List<AdvancedInterface> - PROBLEM
        .map { it.someProperty } // ERROR: Unresolved reference: someProperty
}
w
Well, you'd have to provide a more realistic example. In your case this is actually a problem with
customFilterWithKClass
. It should be
KClass<T>
. Currently it just infers
T
from the receiver list. So the only reason
// 1
works is because
val items
is already of type
Advanced
. There is no realistic use case to call
List<A>.filterIsInstance<B>()
given that
B
is a supertype of
A
. And your compiler output is exactly as you should expect