Reputation: 191
So my goal is use in Kotlin similar construction to Java PECS:
List<? extends MyMarkerInterface> => MutableList<out MyMarkerInterface>
When Jackson set after compiling data to this variable(list) it's ok. When I try to add item from Kotlin code , Kotlin says that I can add only Nothing (type) items.
So how do I put inside List child of MyMarkerInterface in Kotlin?
Upvotes: 0
Views: 378
Reputation: 18607
This is about variance.
(Because Kotlin distinguishes between mutable and immutable lists, it's stricter about this than Java, so you can't always compare directly.)
Suppose you have reference to a MutableList<out MyMarkerInterface>
. That parameter is the equivalent of Java's <? extends MyMarkerInterface>
, and means you have a mutable list of MyMarkerInterface
or some subtype. But you don't know which subtype; it could be any type that implements your interface.
It could be a mutable list of MyImplementingClassA
; so you clearly can't add an instance of MyImplementingClassB
without risking violating its type-safety. Nor vice versa. In fact, without knowing any more about its type, it's not safe to add anything to it. That's why Kotlin won't let you. (The way it does that is by inferring the type Nothing
, which is the ‘bottom’ type and has no values.)
However, if you want to get a value out of the list, you know it's some subtype of MyMarkerInterface
, so you can happily treat it as a MyMarkerInterface
reference.
That's why out
variance means the list is a producer: it can produce values for you safely, but it can't consume values because no type would be safe.
And it's the exact opposite for in
variance, which is the equivalent of Java's ? super
.
(Which is of course the gist of PECS. That exact phrasing only applies to Java — the Kotlin equivalent is ‘Producer Out, Consumer In’, which is probably too obvious to need an acronym! — but the principle's the same.)
The only safe way to be a both producer and a consumer is to be invariant: plain old MutableList<MyMarkerInterface>
. That way, you know that you can get MyMarkerInterface
values out and put MyMarkerInterface
values in.
Things are different for List
s, which are immutable in Kotlin. (Or rather, you can't mutate them through that reference; you may be able to some other way.) Because that reference won't let you put values in, a List
is not acting as a consumer, only a producer, and so out
variance is fine for it.
–
Your question doesn't give any detail, but you mentioned initialisation. It's probably most common to create a List
with all the values it will have up-front — either by calling listOf()
or a constructor, or as the result of a map()
or similar operation.
However, you could also create some type of MutableList
, set it up as needed, and then upcast it to List
(which is a superinterface of MutableList
), e.g.:
val ml = ArrayList<MyImplementingClassA>()
// …some computation which calls ml.add()…
val l = ml as List<out MyMarkerInterface>
…though in practice, you generally wouldn't need that last line; Kotlin knows that List
s have out
variance, and so it'd upcast ml
to List<out MyMarkerInterface>
automatically if needed.
Upvotes: 1
Reputation: 191
Remove out at all, and it works fine but without "? extends" when decompile code from bytecode after Kotlin
Upvotes: 0