arrow icon indicating copy to clipboard operation
arrow copied to clipboard

Proposal to change return type of `shift` to `Nothing`

Open roomscape opened this issue 3 years ago • 0 comments

The shift function in EffectScope and EagerEffectScope is currently declared as

suspend fun <B> shift(r: R): B

Instead it could be declared as

suspend fun shift(r: R): Nothing

Initially proposed in the #kotlinlang Slack.

Benefits

Using Nothing would:

  • Take advantage of the type system to convey information about the behaviour of the function
  • Allow the IDE to warn about unreachable code after a call to shift
  • Allow smart-casting after a call to shift
  • Remove the need to specify a type argument in some cases where omitting it would currently be a compile error

Minimal example that does not compile before the change, but would compile after the change:

val result: Either<String, Int> = either.eager {
    shift("Not an int") // Not enough information to infer type variable B
    1
}

Example of a missed opportunity for a smart cast:

val result: Either<String, Int> = either.eager {
    val x: String? = null
    if (x == null) shift<Any>("Not an int")
    x.toInt() // Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?
}

Comparison with standard library

Nothing is used in a few places in standard Kotlin functions, notably:

  • error: fun error(message: Any): Nothing
  • TODO: fun TODO(): Nothing

There are also examples of bottom/empty types that don't use Nothing, e.g:

The semantics of shift make it more similar to functions like error, so it would be idiomatic to use Nothing here.

Compatibility

  • Nothing is assignable to any type, so any code that uses the return value from shift would continue to compile.
  • ℹ️ A new warning would be introduced because code after a call to shift would be identified as unreachable. This could be a breaking change for anyone using the -Werror compiler flag.
  • Breaking change: calling shift with an explicit generic type, e.g. shift<Nothing>(), would become a compile error when it wasn't before.

roomscape avatar Aug 23 '22 08:08 roomscape