Why does this program prints kotlin.Unit when it should fail with ClassCastException at runtime?
class Animal<T> {
}
fun <T> Animal<T>.extension(block: ()-> T){
print(block())
}
fun main(){
//(4 as Unit) //Runtime ClassCastException, OK
//Animal<String>().extension { 2+2 } //Compilation error, ok
Animal<Unit>().extension { 2+2 } // Why no ClassCastException but prints kotlin.Unit?
}
If this is not a bug, is it possible to enforce the constraint?
Kotlin treats functions that return Unit as a special case when interpreting lambda expressions. If it expects the lambda to return Unit, it will implicitly return Unit regardless of what the last line of the lambda evaluates to. Otherwise, lambdas would very frequently have to have a useless line at the end to return Unit
. So, because of the way it is interpreting the lambda, there is no cast occurring here. There is an implicit extra line returning Unit in your function defined by the lambda.
Suppose you're calling a function that takes a callback parameter fun foo(onComplete: (String)->Unit)
, and you want to add the returned value to a Set:
foo {
someMutableSet.add(it)
}
The add
function returns a Boolean that we don't care about here. It would be annoying if you had to remember to mark it like this:
foo {
someMutableSet.add(it)
Unit
}
This special treatment doesn't just apply to lambdas. You don't have to put a return Unit
line at the end of every traditional function that returns Unit either. And you don't have to explicitly put the return type : Unit
for function signatures either.