kotlingenericscovarianceinvariance

Why does Kotlin produce an Unchecked Cast warning when casting a covariant type parameter to invariant type parameter?


Suppose I have a class Message and a class Channel<T : Message>.

Now, how come I can't cast Channel<out Message> to Channel<Message> without an Unchecked Cast warning?

Shouldn't this cast always be safe since Channel<out Message can only contain objects of type Message or subclasses of type Message?


Solution

  • No, and here is proof.

    class Channel<T : Message> {
      fun send(t: T)
      fun receive(): T
    }
    class Apple : Message()
    class AppleChannel : Channel<Apple>() {
      ...
    }
    
    val appleChannel = AppleChannel()
    val outMessageChannel: Channel<out Message> = appleChannel // MUST WORK
    val messageChannel: Channel<Message> = outMessageChannel 
       // you say this should work, but...
    messageChannel.send(Orange()) 
       // sending orange on a channel that only knows how to send apples!  
       // Error!
    

    The only consistent thing to do is to not allow the conversion of Channel<out Message> to Channel<Message> in this scenario.

    If it were defined as Channel<out T: Message>, then this would be safe, but trying to define send would cause an error.