Smart cast for filter/map idiom

I have a Stream-like scenario (actually a Mono) where I ended up with the chain ...filter { it is X }.map { it as X }... Obviously, this is a little redundant, but it’s not as cumbersome as a full-blown flatMap involving a type-check, unit and empty calls.

I can write an extension function that makes it cleaner, but I’ll have to do that for every Stream-like where I want the shorthand.

inline fun <reified R> Mono<out Any>.smartCast(): Mono<R> = this.filter { it is R }.map { it as R }

....smartCast<X>()...

Is there a better idiom for this? I understand that the language itself can’t smart cast based on an arbitrary function even if it’s a well-known pattern. But I didn’t know if there was a library function or something I was missing.

I don’t know Mono, but the general answer would be to use filterIsInstance<X>(). Failing that, if the type’s non-nullable, you could use filterNotNull{ it as? X }.

1 Like

There already is a function called filterIsInstance<T>, but it only works on Iterables, so it probably won’t work for you. If there is an interface or superclass that all the stream-like classes inherit from, you can define that smartCast function on

If the list contains non null elements, then this achieves the goal for lists:

list.mapNotNull { it as? T }

You could define a similar function for your stream like types.

1 Like

That’s helpful info, thanks.

(Mono is from project-reactor. Just yet another API with a flatMap pattern built in, but no standard super-interface for that behavior, unfortunately.)

1 Like

Fun fact btw, you can probably currently use Arrow with Arrow Meta and define a FunctorFilter extension interface that only has map and filter. Then you can just define an extension function on FunctorFilter that does filterIsInstance. The cool thing about Arrow Meta with the typeproofs plugin is that it will basically allow you to project all of these methods defined on FunctorFilter for any class that has an extension function going from it to a FunctorFilter and back. If you want to explore more, please check out the arrow-kt.io website and the arrow channel on the KotlinLang slack.

1 Like