Explain Array<in T> (a use-site 'in' projection): when would you use it, and what does it do to get and set?
answer
- in = consumer/write, accepts supertype arrays
- set keeps T, get widens to Any?
- fillWithZeros(dest: Array<in Int>)
- in mirrors out exactly
- use for write-only sinks/buffers
basics
~20 sArray<in T> means 'I only write T into this array'. You can call set with a T, and you can pass arrays of supertypes. But reading gives back Any?, because the array may actually hold a broader type.
solid answer
~40 sAn in-projection makes the type parameter contravariant at the use site, turning the array into a consumer of T. set(index, value: T) stays callable because value is in an in-position. In exchange, get loses precision: its return type is projected to Any? (the supertype of all the unknown possible element types). The use case is a sink/destination you only write to. For example fun fillWithZeros(dest: Array<in Int>): you write Ints, and you can pass an Array<Int>, Array<Number>, or Array<Any> because all of them can safely hold an Int. This is the contravariant counterpart of Array<out T>; together they correspond to Java wildcards but expressed with in/out. The key trade-off: in gives you write-with-T but read-as-Any?, while out gives read-as-T but no write.
code
kotlin · 6 linesfun <T> addAll(dest: Array<in T>, src: Array<out T>) {
for (i in src.indices) dest[i] = src[i] // read T from src, write T to dest
}
val target: Array<Any> = arrayOf<Any>(0, 0)
addAll(target, arrayOf("a", "b")) // dest: Array<in String> via Array<Any>go deeper
Recognizes in means writing and that supertype arrays can be passed.
States set stays usable and get widens to Any?, with a destination/sink use case.
Explains why Any? is the only sound read type and pairs in/out in a copy signature.
Frames in/out projections as the use-site encoding of the producer/consumer split, preserving soundness on a mutable invariant type.
## What an in-projection is `Array<in T>` applies **contravariant** variance at the use site. It says "this array is a **consumer** of `T` — I will write `T`-typed values into it". Where `out` was about producing/reading, `in` is about consuming/writing. ## Subtyping it enables With `dest: Array<in Int>`, you may pass any array whose element type is `Int` **or a supertype** of `Int`: ```kotlin fun fillWithZeros(dest: Array<in Int>) { for (i in dest.indices) dest[i] = 0 // set(value: Int) is allowed } fillWithZeros(arrayOf(1, 2, 3)) // Array<Int> fillWithZeros(arrayOf<Number>(1, 2, 3)) // Array<Number> fillWithZeros(arrayOf<Any>(1, 2, 3)) // Array<Any> ``` All are safe destinations for an `Int`, because an `Int` is a `Number` and an `Any`. ## Effect on members Kotlin again looks at the position of `T`: - `set(index: Int, value: T)` — `T` is in an **in-position** → **kept**; you can pass an `Int`. - `get(index: Int): T` — `T` is in an **out-position** → **projected**; its return type becomes `Any?`. ```kotlin fun demo(dest: Array<in Int>) { dest[0] = 42 // OK: set val x = dest[0] // x: Any? (precise type lost) } ``` ## Why `get` returns `Any?` The real array might be `Array<Any>`, so an element could be any object. The only type guaranteed to describe every possible element is `Any?` (nullable `Any`, the top type). The compiler therefore widens the read result to `Any?`. ## Mirror summary | Projection | get returns | set accepts | Accepts arrays of | |---|---|---|---| | `Array<out T>` | `T` | nothing (`Nothing`) | `T` and subtypes | | `Array<in T>` | `Any?` | `T` (and subtypes) | `T` and supertypes | ## When to use it Use `Array<in T>` for a **write-only destination** parameter — a buffer you fill, a sink you push into. Use `Array<out T>` for a **read-only source**. This is the use-site, per-parameter way to express the producer/consumer split.
- Why does get return Any? rather than T under an in-projection?Because the underlying array's element type is some unknown supertype of T, so the only sound static type for a read is the top type Any?.
Array<in T> is a mailbox slot: you can drop T-shaped letters in (set), but if you peek inside you only know it's 'some object' (Any?).
saying these in an interview costs you the question
- Saying in lets you read elements as T
- Claiming in accepts subtype arrays (it accepts supertypes)
- Forgetting that set stays callable under in
- Confusing in-projection with declaration-site contravariance on the class
- Saying get is forbidden entirely under in (it returns Any?, not blocked)