I have a generic interface which accepts all kinds...
# getting-started
j
I have a generic interface which accepts all kinds of values, I cannot declare the generic type as
out
since the
get()
accepts this same type as a parameter:
Copy code
interface MyInterface<T> {
    val inner: T
    fun get(other: T): String
}
I want this interface to be iterable when the generic type is also an iterable, so I add this extension function:
Copy code
operator fun <T> MyInterface<Iterable<T>>.iterator(): Iterator<T> = TODO()
However, when using this interface, I cannot iterate over it:
Copy code
fun doSomething(payload: MyInterface<Set<Any>>) {
    for (row in payload) { /* ... */ }
                ^ COMPILE ERROR: For-loop range must have an 'iterator()' method
}
If I declare the generic type as
out
, the compiler no longer complains about a missing
iterator()
method, but the
MyInterface::get(T)
method cannot compile anymore since the generic type is
out
(while also used as an
in
by this method). From what I understand, it seems that Kotlin accepts to iterate over a type even if it doesn’t explicitly implement the
Iterable<T>
interface, as long as an
iterator(): Iterator<T>
method exists
. However, it doesn’t seem to work when the generic type is not defined as
out
, despite being both
in
and
out
here in my first example. Am I missing/abusing something or is this a bug in the language?
s
Copy code
operator fun <T, I: Iterable<T>> MyInterface<I>.iterator(): Iterator<T> = TODO()
👍 1
☝️ a potential solution
there might be better ways 😄
j
wtf haha
is this magic?!
I’m having a hard time understanding what you’ve done, but you did it!
Would you mind explaining me how this works?
oooh, I think I understand why your solution works, but is it not showing a bug in the language?
s
MyInterface<Iterable<T>>
says that the type must be exactly
Iterable<T>
, whereas
MyInterface<I>
where
I: Iterable<T>
is one way to say it can be any subtype of
Iterable<T>
.
Another way is
Copy code
operator fun <T> MyInterface<out Iterable<T>>.iterator(): Iterator<T> = TODO()
☝️ 1
💯 1
You described the type as “both
in
and `out`”, but I think that might indicate a misunderstanding. If a type is used only as an input, it can have
in
variance, and if it’s used only as an output, it can have
out
variance, but if it’s used as both an input and an output, it cannot have any variance (i.e. it’s neither in nor out). That’s the default, if variance is not specified.
j
Thank you for your explanations, it is much more evident now!