stdout
stdout

Reputation: 2651

Understanding one usage of "in" keyword in Kotlin

I'm trying to understand Kotlin take of generics especially with the in and out keywords. I've written this simple piece to hopefully illustrate my point of confusion.

This is the method that looks and works OK;

enter image description here

Here, IDE gives a hint saying that the type of the item the for loop is iterating over is a Shape. This is good.

Another version of the method above that doesn't seem quite right at first glance (since it's a "consumer"). But all I want to do is to read a list of shapes and that's all what's in this from.

enter image description here

That doesn't work which is maybe right according to the rules but I am not able to connect the dots here. It seems like a safe operation. I can also see Kotlin downs the type to "Any?" which explains why this gives a compiler error already. Can someone explain the potential type unsafety here please?

Upvotes: 0

Views: 447

Answers (1)

gidds
gidds

Reputation: 18577

Variance is always a tough concept to work through…

If you're using the terms ‘producer’ and ‘consumer’, note that they refer to your interaction with the item in question ‚ in this case, the MutableList parameter.

Your first function, with a MutableList<out Shape> parameter, can accept a list of Shapes, or a list of any subclass of Shape.  (out means roughly ‘or any subclass’.)

In each case, if you're consuming the list, whatever you pull out of the list will always be a Shape (as the IDE confirms).

But if you want to put something into the list (as a producer), you can't tell what would be safe to add, as that would depend on whether it's a subclass, and which one.

Your second function, with a MutableList<in Shape> parameter, is the opposite: it can accept a list of Shapes, or a list of any superclass of Shape.  (in means roughly ‘or any superclass’.)

In each case, it's always safe to put a Shape into the list (as a producer).  But you can't tell anything about the type of what you pull out of it (as a consumer): it could be called with a MutableList<Any?>, which could contain Strings or Files or whatever.  So the compiler will give it the universal type, Any? (as the IDE confirms).

Upvotes: 5

Related Questions