arrow
arrow copied to clipboard
Proposal to change return type of `shift` to `Nothing`
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:
There are also examples of bottom/empty types that don't use Nothing, e.g:
- emptyList
fun <T> emptyList(): List<T>
The semantics of shift make it more similar to functions like error, so it would be idiomatic to use Nothing here.
Compatibility
- ✅
Nothingis assignable to any type, so any code that uses the return value fromshiftwould continue to compile. - ℹ️ A new warning would be introduced because code after a call to
shiftwould be identified as unreachable. This could be a breaking change for anyone using the-Werrorcompiler flag. - ❌ Breaking change: calling
shiftwith an explicit generic type, e.g.shift<Nothing>(), would become a compile error when it wasn't before.