Star projection, written `*`, represents a generic argument whose exact type is unknown or irrelevant. Use it when the generic container or interface matters but its particular type argument does not. For example, `List<*>` lets code recognize a list at runtime without claiming that it is a `List<String>` or `List<Int>`—information erased from generic types at runtime. section 11.2.1 section 11.4
Read unknown elements safely
```kotlin fun printFirst(list: List<*>) { if (list.isNotEmpty()) { println(list.first()) } } ``` `list.first()` is safe because an element from an unknown list can be viewed as `Any?`. The function can accept lists with different element types, while making no promise about which element type any caller supplied. section 11.3.6
For mutable invariant collections, unknown is not the same as broad. `MutableList<Any?>` is known to accept values of any type, so code may add to it. `MutableList<*>` was created for one specific element type that is hidden from the current code; adding `42`, or any other value, could break that original expectation. Kotlin therefore allows reads but rejects writes. section 11.3.6
Unknown mutable list
```kotlin val values: MutableList<*> = if (Random.nextBoolean()) mutableListOf('a', 1) else mutableListOf('a', 'b') println(values.first()) // values.add(42) // error ``` The star projection acts as `MutableList<out Any?>`: it exposes produced values as `Any?` but prohibits supplying an element. section 11.3.6
Use star projections in these practical situations:
- Check a generic class at runtime when only its base type is knowable: `if (value is List<*>) { ... }`. section 11.2.1
- Store differently typed generic implementations behind a common registry type, such as `MutableMap<KClass<*>, FieldValidator<*>>`. section 11.3.6
- Describe annotation class references whose generic implementation type is constrained but whose argument varies: `KClass<out ValueSerializer<*>>`. section 12.1.7
A star-projected consumer is deliberately hard to call. With `FieldValidator<in T>`, `FieldValidator<*>` hides the input type, so `validate(...)` is rejected: code cannot know what value the validator accepts. Recovering a specific `FieldValidator<String>` requires an explicit cast, which can fail later if the registry entry actually validates another type. Encapsulate such unchecked casts behind typed registration and lookup APIs where possible. section 11.3.6
Star projection corresponds to Java’s unbounded wildcard form, `MyType<?>`. It is not a replacement for a useful type parameter: if a function can preserve the caller’s element type, a generic signature such as `fun <T> printFirst(list: List<T>)` retains more type information than `List<*>`. Choose `*` when that information is genuinely unavailable or unnecessary. section 11.3.6
import kotlin.random.Random
fun main() {
val list: MutableList<Any?> = mutableListOf('a', 1, "qwe")
val chars = mutableListOf('a', 'b', 'c')
val unknownElements: MutableList<*> = #1
if (Random.nextBoolean()) list else chars
println(unknownElements.first()) #2
// a
unknownElements.add(42) #3
// Error: Out-projected type 'MutableList<*>' prohibits
// the use of 'fun add(element: E): Boolean'
}
Compare a mutable list known to accept `Any?` with a star-projected list that can be read but not written. section 11.3.6
