Rob Elliot
01/05/2022, 4:13 PM<T>
as <T & Any>
in some circumstances if you also use it as <T?>
.Youssef Shoaib [MOD]
01/06/2022, 10:27 AMabstract class GenericMapper<out T>
(playground)
I think it breaking shows that it's not necessarily treating the <T>
in nonNull
as <T & Any>
, but more that it's actually declaring that no matter what T is, GenericMapper has to accept a nullable T, and of course DisNonNullable
doesn't accept that. Think of it that because T is invariant, DisNonNullable
could have a method that consumes T, and of course then it can't consume nulls, and so if it was allowed to call nonNull
with its GenericMapper<T?>
that can cause issues.Rob Elliot
01/06/2022, 11:02 AMfun <T : Any> GenericMapper<T?>.nonNull()
, I presume because T : Any
is a subtype of T?
, so GenericMapper<String>
is a subtype of GenericMapper<String?>
, so the extension function applies.Youssef Shoaib [MOD]
01/06/2022, 11:54 AMfun main(args: Array<String>) {
DisNullable.nonNull()
DisNonNullable.nonNull()
}
abstract class GenericMapper<out T> {
abstract fun map(string: String): T
}
fun <T> GenericMapper<T?>.nonNull(): GenericMapper<T> {
val delegate = this
return object : GenericMapper<T>() {
override fun map(string: String): T {
return delegate.map(string) ?: TODO("handle null")
}
}
}
@Deprecated(message = "Don't use this", ReplaceWith("this"), DeprecationLevel.ERROR)
@JvmName("non-null")
fun <T: Any> GenericMapper<T>.nonNull(): GenericMapper<T> = TODO()
object DisNullable : GenericMapper<String?>() {
override fun map(string: String) = string
}
object DisNonNullable : GenericMapper<String>() {
override fun map(string: String) = string
}
That's also a solution to the original, so yay freebie