# Exercise about generics from Kotlin Education presentation

**URL:** <https://discuss.kotlinlang.org/t/exercise-about-generics-from-kotlin-education-presentation/27885>\
**Category:** Support\
**Created:** [December 31, 2023, 1:08pm UTC](https://discuss.kotlinlang.org/t/exercise-about-generics-from-kotlin-education-presentation/27885 "2023-12-31T13:08:03Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Heci\_Pan](https://avatars.discourse-cdn.com/v4/letter/h/5daacb/32.png) [@Heci\_Pan](https://discuss.kotlinlang.org/u/Heci_Pan)\
**Post date:** [December 31, 2023, 1:08pm UTC](https://discuss.kotlinlang.org/t/exercise-about-generics-from-kotlin-education-presentation/27885/1 "2023-12-31T13:08:03Z")

</div>

There is a presentation about generics on [Kotlin for Education](https://kotlinlang.org/education/) At the end there is a exercise. I can’t figure out how to solve this by changing only `????`.

```auto
open class A
class B : A()
class C : A() { fun consume(other: A): C = this }

fun <T, S : R, R> funny(
   source: Iterator<????>,
   target: MutableCollection<????>,
   base: ????,
   how: ????
) {
   var result: R = base
   for (value in source) {
       result = how(result, value)
       target.add(result)
   }
}

fun main() {
   val wtf = mutableListOf<A>()
   val src = mapOf(3.14 to B(), 2 to B(), "Hello" to B())
   val c = C()
   funny(src.values.iterator(), wtf, c) { r, t -> r.consume(t) }
}

```

Is it possible to solve this by changing only `????`? If yes, how to do it?

---

<div class="post-metadata">

**Author:** ![Skater901](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/skater901/32/10163_2.png) [@Skater901](https://discuss.kotlinlang.org/u/Skater901)\
**Post date:** [January 1, 2024, 11:39am UTC](https://discuss.kotlinlang.org/t/exercise-about-generics-from-kotlin-education-presentation/27885/2 "2024-01-01T11:39:37Z")

</div>

Man this is a doozy of a problem.

I would start by noting the actual types passed to the different parameters of `funny`, then work from there. So `source` will be an `Iterator<B>`, `target` will be a `MutableCollection<A>`, `base` will be `C`.

So then let’s work through our function. `var result: R = base`… so `base` is either `S` or `R`. So in our use case, `S` or `R` becomes `C`.

`for (value in source)`, `source` is an `Iterator<B>`, so each `value` is `B`. Not much we can really infer there.

`result = how(result, value)`, now this is pretty interesting. This is clearly an accumulator function of some kind. Since we know `result` is `R`, and this `how` function takes `result` and returns `result`, we know the signature is `how: (R, ????) -> R`.

`target.add(result)`, so this tells us that `target` must be a `MutableCollection<R>`, since `result` is `R` and you can add `result` to `target`.

So… now we have this:

```auto
fun <T, S : R, R> funny(
   source: Iterator<????>,
   target: MutableCollection<R>,
   base: ????,
   how: (R, ?) -> R
)

```

Looking at our example some more… `var result: R = base`. Now if we know that `target` is type `R`, and in our example, `R` is `A`, since `target` is `wtf`, our mutable list of `A`, `base` is `c`, an instance of our `C` class, which extends `A`. So similarly, `base` must be of type `S`, since `S` extends `R`.

```auto
fun <T, S : R, R> funny(
   source: Iterator<????>,
   target: MutableCollection<R>,
   base: S
   how: (R, ?) -> R
)

```

At this point, I’m assuming that `source` and `how` use `T`, because otherwise it wouldn’t be used… and also, since in our example, `R` is `A`, `S` is `C`, `B` cannot be `R` or `S`. Ergo… `B` becomes our `T` type.

```auto
fun <T, S : R, R> funny(
   source: Iterator<T>,
   target: MutableCollection<R>,
   base: S
   how: (R, T) -> R
)

```

I think that’s the answer. I haven’t tested my code though, so maybe I’m wrong. 🙂

Does that explanation make sense? Were you able to follow my logic? It’s pretty confusing… especially since the classes are all single letters, like the types.

---

<div class="post-metadata">

**Author:** ![Heci\_Pan](https://avatars.discourse-cdn.com/v4/letter/h/5daacb/32.png) [@Heci\_Pan](https://discuss.kotlinlang.org/u/Heci_Pan)\
**Post date:** [January 1, 2024, 12:29pm UTC](https://discuss.kotlinlang.org/t/exercise-about-generics-from-kotlin-education-presentation/27885/3 "2024-01-01T12:29:23Z")

</div>

Thanks for extensive explanation. Unfortunately it doesn’t work without adding `(r as C)` to `r.consume(t)`. I’m still wondering if this is possible to solve it without adding `(r as C)` 🤔

---

<div class="post-metadata">

**Author:** ![Skater901](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/skater901/32/10163_2.png) [@Skater901](https://discuss.kotlinlang.org/u/Skater901)\
**Post date:** [January 1, 2024, 12:45pm UTC](https://discuss.kotlinlang.org/t/exercise-about-generics-from-kotlin-education-presentation/27885/4 "2024-01-01T12:45:36Z")

</div>

Huh, that’s a very good point…

I don’t think this function can actually work, then. Since `result` is of type `R`, and `R` doesn’t extend anything, the signature of `how` _has_ to be `(R, ?) -> R`, but then the provided lambda wouldn’t work, since if `R` is `A`, there’s no `consume` function on `A`, and if `R` is `C`, then that wouldn’t make sense, because `S` extends `R`, but nothing extends `C`.

Are you sure this is copied as-is from the Kotlin learning site?

---

<div class="post-metadata">

**Author:** ![Heci\_Pan](https://avatars.discourse-cdn.com/v4/letter/h/5daacb/32.png) [@Heci\_Pan](https://discuss.kotlinlang.org/u/Heci_Pan)\
**Post date:** [January 1, 2024, 12:47pm UTC](https://discuss.kotlinlang.org/t/exercise-about-generics-from-kotlin-education-presentation/27885/5 "2024-01-01T12:47:41Z")

</div>

> Are you sure this is copied as-is from the Kotlin learning site?

Yes, this exercise is at the end of the presentation about \* [Generics](https://docs.google.com/presentation/d/1R7n5plsn5caGpYrI9omxbEuX6pazjDj2d9X0IQ2AdLg/edit?usp=drive_link)

---

<div class="post-metadata">

**Author:** ![Skater901](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/skater901/32/10163_2.png) [@Skater901](https://discuss.kotlinlang.org/u/Skater901)\
**Post date:** [January 1, 2024, 12:56pm UTC](https://discuss.kotlinlang.org/t/exercise-about-generics-from-kotlin-education-presentation/27885/6 "2024-01-01T12:56:43Z")

</div>

I don’t think it’s possible… unless someone smarter than me can come along and explain it. `how` has to be `(R, ?) -> R` or `(R, ?) -> S`, not that it makes much difference since the result is just assigned back to `R`, so even if it was `(R, ?) -> S`, you’d lose the fact that the return type was `S`. `target` _has_ to be `MutableCollection<R>` since we’re putting `result`, which is `R`, into it. `funny` is being called with `wtf` as the `target`, and `wtf` is mutable list of `A`, therefore `R` _has_ to be `A`… but then `how` becomes `(A, ?) -> A`, and the lambda doesn’t work.

I can’t see a way you can make this code work as-is, just by filling in the types. It needs type casting. Unless I’m missing something, which is always possible.

---

<div class="post-metadata">

**Author:** ![kyay10](https://avatars.discourse-cdn.com/v4/letter/k/c57346/32.png) [@kyay10](https://discuss.kotlinlang.org/u/kyay10)\
**Post date:** [January 1, 2024, 2:27pm UTC](https://discuss.kotlinlang.org/t/exercise-about-generics-from-kotlin-education-presentation/27885/7 "2024-01-01T14:27:33Z")

</div>

It’s a generics exercise… So, of course, this is the solution:

```auto
fun <T, S : R, R> funny(
   source: Iterator<T>,
   target: MutableCollection<in R>,
   base: S,
   how: (R, T) -> R
)

```

The `in R` allows R to be narrowed down to `C` instead of being upcast to `A`. I really don’t see the point of having `S` though.

---

<div class="post-metadata">

**Author:** ![Skater901](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/skater901/32/10163_2.png) [@Skater901](https://discuss.kotlinlang.org/u/Skater901)\
**Post date:** [January 3, 2024, 6:14am UTC](https://discuss.kotlinlang.org/t/exercise-about-generics-from-kotlin-education-presentation/27885/8 "2024-01-03T06:14:37Z")

</div>

Wouldn’t `base` have to be `R`? Even if `target` is `MutableCollection<in R>`, with the way it’s called, I think `R` would still become `A`, which means `how` is taking an `A`, not a `C`, and the lambda doesn’t work.

---

<div class="post-metadata">

**Author:** ![kyay10](https://avatars.discourse-cdn.com/v4/letter/k/c57346/32.png) [@kyay10](https://discuss.kotlinlang.org/u/kyay10)\
**Post date:** [January 3, 2024, 10:29am UTC](https://discuss.kotlinlang.org/t/exercise-about-generics-from-kotlin-education-presentation/27885/9 "2024-01-03T10:29:22Z")

</div>

It compiles!  
But to your question, base being R or S doesn’t actually change anything at all. For the sake of simplicity, I’ll talk about a non-S version of the function. The way it’s called basically provides 2 hints for the type of `R`: a `target: MutableCollection<in A>` and a `base: C`. Because we’re using `in`, the compiler is free to narrow down the type from `A` to `C`, and for some compiler spec reason, it prefers the narrower type. I think, very specifically, the information coming from the lambda is only analyzed _after_ this is determined, so only those 2 hints are used. Importantly, without `in`, `R` can _only_ be `A`, because `MutableCollection` is invariant.

```run-kotlin
open class A
class B : A()
class C : A() { fun consume(other: A): C = this }

fun <T, S : R, R> funny(
   source: Iterator<T>,
   target: MutableCollection<in R>,
   base: R,
   how: (R, T) -> R
) {
   var result: R = base
   for (value in source) {
       result = how(result, value)
       target.add(result)
   }
}

fun main() {
   val wtf = mutableListOf<A>()
   val src = mapOf(3.14 to B(), 2 to B(), "Hello" to B())
   val c = C()
   funny(src.values.iterator(), wtf, c) { r, t -> r.consume(t) }
}

```
