# Using values of projected types as arguments, for parameters of projected types

**URL:** https://discuss.kotlinlang.org/t/using-values-of-projected-types-as-arguments-for-parameters-of-projected-types/27600
**Category:** Support
**Created:** [November 7, 2023, 7:09am UTC](https://discuss.kotlinlang.org/t/using-values-of-projected-types-as-arguments-for-parameters-of-projected-types/27600 "2023-11-07T07:09:33Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![V2](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/v2/32/10235_2.png) [@V2](https://discuss.kotlinlang.org/u/V2)
#### Post date: [November 7, 2023, 7:09am UTC](https://discuss.kotlinlang.org/t/using-values-of-projected-types-as-arguments-for-parameters-of-projected-types/27600/1 "2023-11-07T07:09:33Z")

</div>

Hello, in order to understand variance better I have created this testing code:

```auto
val number: Number = 1f

class Box<T>(var item: T)

val numberBox: Box<Number> = Box(1f)
val outNumberBox: Box<out Number> = Box(2)
val inNumberBox: Box<in Number> = Box<Any?>("3")

fun <T : Number> numberBoxHandler(box: Box<T>, t: T) {}
fun <T : Number> outNumberBoxHandler(box: Box<out T>, t: T) {}
fun <T : Number> inNumberBoxHandler(box: Box<in T>, t: T) {}

```

Here are the testing functions:

```auto
//(test 1)
//OK
numberBoxHandler(numberBox, number)
  
//(test 2)
//ERROR at `number`: Type mismatch. Required: CapturedType(out Number) Found: Number
numberBoxHandler(outNumberBox, number)

//(test 3)
//ERROR at `inProjectedNumberBox`: Type mismatch. Required: Number Found: Number
//ERROR at `number`: Type mismatch. Required: Number Found: Number
numberBoxHandler(inNumberBox, number)

//(test 4)
//OK
outNumberBoxHandler(numberBox, number)

//(test 5)
//OK
outNumberBoxHandler(outNumberBox, number)

//(test 6)
//ERROR at `inProjectedNumberBox`: Type mismatch. Required: Number Found: Number
//ERROR at `number`: Type mismatch. Required: Number Found: Number
outNumberBoxHandler(inNumberBox, number)

//(test 7)
//OK
inNumberBoxHandler(numberBox, number)

//(test 8)
//ERROR at `number`: Type mismatch. Required: CapturedType(out Number) Found: Number
inNumberBoxHandler(outNumberBox, number)

//(test 9)
//OK
inNumberBoxHandler(inNumberBox, number)

```

&nbsp;

* * *

I couldn’t make sense of the errors.

> Type mismatch. Required: CapturedType(out Number); Found: Number

What is this `CapturedType`? It is not a function nor a class as far as I know.

> Type mismatch. Required: Number; Found: Number

Why is it a mismatch?

---

<div class="post-metadata">

### Author: ![clovisai](https://avatars.discourse-cdn.com/v4/letter/c/a9adbd/32.png) [@clovisai](https://discuss.kotlinlang.org/u/clovisai)
#### Post date: [November 12, 2023, 1:35pm UTC](https://discuss.kotlinlang.org/t/using-values-of-projected-types-as-arguments-for-parameters-of-projected-types/27600/2 "2023-11-12T13:35:01Z")

</div>

Great examples!

First, you’re right that `CapturedType()` is not a function or a class. I’m not an expert, but I believe it is an internal of the compiler.

I’m not sure which examples you understand or not, so let’s go through all the ones that fail.

### Test 2

First, notice that

```kotlin
val outNumberBox: Box<out Number> = Box(2)

```

is the same as

```kotlin
val intBox: Box<Int> = Box(2)
val outNumberBox: Box<out Number> = intBox

```

`out Number` does not mean “any type that subtypes `Number`”, it means “a specific type that subtypes `Number`, but I don’t necessarily know which one”.

This is why this example fails:

```kotlin
//ERROR at `number`: Type mismatch. Required: CapturedType(out Number) Found: Number
numberBoxHandler(outNumberBox, number)

```

Imagine if the function re-assigned `Box.item`: this would try to reassign `outNumberBox`, which is a `Box<Int>` with `number`, which is `Float`: of course, this is not safe.

### Test 3

Sadly, the error message here is particularly unhelpful.

Let’s consider what would happen if it was allowed:

- you create a `Box("3")` which is up-casted to `Box<Any?>` then `Box<in Number>`
- you try to pass it to a function that accepts a type parameter, and two values that must conform to it.

It’s unclear to me what the compiler infers to be the type parameter here. To make it easier to analyse, let’s force it:

```kotlin
numberBoxHandler<Number>(inNumberBox, number)

```

Now, the compiler doesn’t complain about the `number` parameter. However, it does still complain about `intNumberBox`.

So what if it didn’t complain? Again, the `numberBoxHandler` could contain an assignment to `Box.item`, but `inNumberBox` is “a box of a specific supertype of `Number`”.

Compare how the compiler behaves:

```kotlin
Box<Any?>("3").item = "foo" // allowed
(Box<Any?>("3") as Box<in Number>).item = "foo" // forbidden, the compiler doesn't know if this is safe

```

In the first case, the compiler is sure that any type is allowed, so `String` must be allowed. In the second case, the compiler doesn’t know which type is allowed, only that whichever it is, it must be a supertype of `Number`.

### Test 6

You can understand `out` as the modifier for values that an external actor can only read. Before looking at your example, notice what happens if you write:

```kotlin
outNumberBox.item = 2.0
// ERROR: Setter for 'item' is removed by type projection

```

By using `out`, we have effectively made the value read-only.

`in` is the opposite, it allows only setting the value. We can still read the value, but we will get a `Any?`, so we cannot do anything with it.

Now, let’s look at the example:

```kotlin
outNumberBoxHandler(inNumberBox, number)

```

We are saying that:

- the function expects to be able to read the value of the first argument as a `Number`, but doesn’t care about setting it
- the first parameter can only be read as `Any?`

As you can see, this is incompatible.

Note that the compiler is more paranoid about `in` than it is about `out`. There are multiple things that are mathematically safe with contravariance that the compiler refuses because it is considered too surprising. For example:

```kotlin
interface Foo {
    fun accept(a: Int): Number
}

// allowed, because function return types are 'out'
class Variance : Foo {
    override fun accept(a: Int): Int
}

// mathematically sound, because function parameters are 'in', 
// but still forbidden in Kotlin
class Contravariance : Foo {
    override fun accept(a: Number): Number
}

```

### Test 8

I wish the compiler gave a way to display what type parameter it inferred. Anyway, here, the only type parameter you can use without changing the behavior is:

```kotlin
inNumberBoxHandler<Nothing>(outNumberBox, number)

```

I believe in this case the compiler inferred that the only possible type that could satisfy the first argument’s constraints is `Box<Nothing>`, because iit would be impossible to set it anyway, so all constraints on what values are used to set it are validated (through vacuous truth). However, if it is `Nothing`, then no value of that type exists—so the second argument doesn’t make sense.

* * *

Note that I’m not an expert on any of these questions, and there’s a chance I’m completely wrong about some of these explanations.

In practice, these complex cases are quite rare, because you either have mutable types, which are better left invariant, or read-only types, which you can safely use `out` with, without surprises. `in` is relatively rare to see.

---

<div class="post-metadata">

### Author: ![V2](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/v2/32/10235_2.png) [@V2](https://discuss.kotlinlang.org/u/V2)
#### Post date: [November 14, 2023, 2:23am UTC](https://discuss.kotlinlang.org/t/using-values-of-projected-types-as-arguments-for-parameters-of-projected-types/27600/3 "2023-11-14T02:23:58Z")

</div>

Thanks for such a detailed response, I really appreciate your effort in going through all of the tests! 😃

Thanks to the answer I also realize that the tests are actually not good for demonstrating the behaviors.

For instance:

```auto
val int: Int = 1
val numberBox: Box<Number> = Box<Number>(number)
fun <T : Number> numberBoxHandler(box: Box<T>, t: T) {}

```

Here it might look as if the function is invoked with `Int` as the type argument for `T`:

```auto
numberBoxHandler(numberBox, int)

```

But the actual type argument is `Number`

```auto
numberBoxHandler<Number>(numberBox, int)

```

&nbsp;

I will come back to this

---

<div class="post-metadata">

### Author: ![V2](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/v2/32/10235_2.png) [@V2](https://discuss.kotlinlang.org/u/V2)
#### Post date: [November 14, 2023, 3:52am UTC](https://discuss.kotlinlang.org/t/using-values-of-projected-types-as-arguments-for-parameters-of-projected-types/27600/4 "2023-11-14T03:52:33Z")

</div>

This gets interesting, I found an example where providing explicit type argument is impossible!

```auto
class Box<T>(var item: T)
  
fun <T : Number> numberBoxConsumer(box: Box<T>) {}
  
val numberBox: Box<Number> = Box(1)
val outNumberBox: Box<out Number> = Box(2f)

numberBoxConsumer(numberBox) //(1) OK
numberBoxConsumer<Number>(numberBox) //(2) OK, same as above but with explicit type argument

numberBoxConsumer(outNumberBox) //(3) OK, but this is a bit starnge
numberBoxConsumer<X>(outNumberBox) //(4) providing explicit type argument is impossible!

```

It is impossible to supply a type argument to (4) to make the code compilable!  
Naturally the explicit type argument should be `out Number`, but type projection on function type arguments is forbidden so that cannot be done.  
Similarly star projection is also forbidden because it is just a type of type projection.

---

<div class="post-metadata">

### Author: ![V2](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/v2/32/10235_2.png) [@V2](https://discuss.kotlinlang.org/u/V2)
#### Post date: [November 14, 2023, 4:05am UTC](https://discuss.kotlinlang.org/t/using-values-of-projected-types-as-arguments-for-parameters-of-projected-types/27600/5 "2023-11-14T04:05:32Z")

</div>

If I had to try and explain the behavior of (3), perhaps it is because  
of basic generics, where a single generic function:

```auto
fun <T : Number> numberBoxConsumer(box: Box<T>) {}

```

Can be “expanded” into multiple functions:

```auto
fun <Number> numberBoxConsumer(box: Box<Number>) {}
fun <Int> numberBoxConsumer(box: Box<Int>) {}
fun <Float> numberBoxConsumer(box: Box<Float>) {}
/* etc. */

```

And since `out Number` represents a range of types, i.e. `Number` and its sub types, `Float`, `Int`, etc., the compiler “auto-magically” resolved the types, and therefor (3) compiles.

Thoughts?

---

<div class="post-metadata">

### Author: ![V2](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/v2/32/10235_2.png) [@V2](https://discuss.kotlinlang.org/u/V2)
#### Post date: [November 29, 2023, 11:59am UTC](https://discuss.kotlinlang.org/t/using-values-of-projected-types-as-arguments-for-parameters-of-projected-types/27600/6 "2023-11-29T11:59:16Z")

</div>

[https://youtrack.jetbrains.com/issue/KT-63376/Type-mismatch-when-using-values-of-projected-types-as-arguments-for-parameters-of-projected-types#focus=Comments-27-8469217.0-0](https://youtrack.jetbrains.com/issue/KT-63376/Type-mismatch-when-using-values-of-projected-types-as-arguments-for-parameters-of-projected-types#focus=Comments-27-8469217.0-0)
