Kotlin extension function for nullable types ONLY

78 Views Asked by At

Examine this code:

fun f(nullString: String?, nonNullString: String) {
    nullString.ext() // Error: Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?
    nullString.nullExt() // OK, nullabilities match
    nonNullString.ext() // OK, nullabilities match
    nonNullString.nullExt() // Expected error: nullExt is only applicable to String?
}

I would like to write two function signatures that makes the first and last function call not compile.

This makes the first line a compile error, but the last line still compiles:

fun String.ext(): Unit = TODO()
fun String?.nullExt(): Unit = TODO()

As far as I understand this works because "String extends String?", so defining an extension on String? is similar to defining one on CharSequence. Is there a way to prevent this from compiling?

1

There are 1 best solutions below

2
TWiStErRob On

A possible solution is to forbid the compiler to pick the "super" implementation, by declaring a more specific one:

fun String.ext(): Unit = TODO()
fun String?.nullExt(): Unit = TODO()

@Deprecated(
    message = "nullExt is only applicable to nullable receivers.",
    level = DeprecationLevel.ERROR,
    replaceWith = ReplaceWith("")
)
fun String.nullExt(): Unit =
    error("This should never be called.")

Note: String! will resolve to String overload.


A real use case in case anyone is wondering:

fun <T : Any?> T?.orError(message: String): T & Any =
    this ?: error(message)

@Deprecated(
    message = "orError is only applicable to nullable receivers.",
    level = DeprecationLevel.ERROR,
    replaceWith = ReplaceWith("")
)
fun <T : Any> T.orError(message: String): Nothing =
    error("This should never be called.")

we wouldn't want somethingNonNull.orError() because in that case orError() will never execute and therefore it is dead code.