liveBook · Manning

Type argument

As explained in Kotlin in Action, 2E

A type argument is an argument supplied to a parameterized construct to specify a type or constrain the kinds of values it accepts.

A type argument supplies a concrete type wherever a generic class, interface, or function has a type parameter. `List<String>` says a list holds strings; `Map<String, Person>` supplies separate arguments for keys and values. Kotlin requires every generic type argument to be explicit or inferred, unlike Java raw types such as `ArrayList` without an element type. section 11.1

Specify an argument only when inference needs help

The compiler infers `String` from the values passed to `listOf`, so the result is `List<String>`. An empty collection has no values to reveal its element type, so provide it either on the variable or the factory function. `val authors = listOf("Sveta", "Seb")` `val readers: MutableList<String> = mutableListOf()` `val readers = mutableListOf<String>()` section 11.1

Generic functions receive type arguments at each call. Usually Kotlin infers them from the receiver and arguments, then substitutes the result type accordingly. Calling `slice` on a `List<Char>` produces `List<Char>`; explicit syntax such as `slice<Char>(0..2)` remains available when it improves clarity or inference cannot determine the type. section 11.1.1

Listing 11.1 Calling a generic function
fun main() {
    val letters = ('a'..'z').toList()
    println(letters.slice<Char>(0..2))   #1
    // [a, b, c]
    println(letters.slice(10..13))       #2
    // [k, l, m, n]
}

Compare an explicit function type argument with the inferred form; both calls return a list of characters. section 11.1.1

Type arguments also determine what a generic declaration can safely express:

  • A generic class uses its parameter in member types: `List<T>` can return `T`, while `StringList : List<String>` returns `String`. section 11.1.2
  • Upper bounds restrict eligible arguments. `<T : Number>` accepts numeric subtypes, and `<T : Comparable<T>>` requires values comparable with their own type. section 11.1.3
  • An unconstrained parameter accepts nullable arguments because its effective upper bound is `Any?`; `<T : Any>` excludes nullable types. section 11.1.4
  • Nested and nullable arguments form distinct types, such as `List<Int>`, `List<String?>`, and `List<List<String>>`. section 11.3.2

On the JVM, ordinary type arguments are checked by the compiler but erased at run time. A `List<String>` and `List<Int>` are both only a `List` at execution, so `is List<String>` is not allowed. The compiler still preserves static safety unless casts or Java raw types bypass it. section 11.2.1

Reify a function argument for a runtime check

An inline function can mark its parameter `reified`, making the actual argument available in its inlined body. This enables `is T` checks and supports utilities such as `filterIsInstance<String>()`, which selects strings from a mixed collection and returns `List<String>`. `inline fun <reified T> isA(value: Any) = value is T` section 11.2.2

Type arguments also affect subtype relationships. Kotlin permits `List<String>` where `List<Any>` is expected because read-only `List` is covariant, but rejects `MutableList<String>` as `MutableList<Any>` because a consumer could add a non-string. Use-site `out` and `in` projections express corresponding producer and consumer constraints, paralleling Java bounded wildcards. section 11.3.1 section 11.3.5

When the exact argument is unknown or irrelevant, a star projection can stand in for it. For example, an annotation parameter can use `KClass<out ValueSerializer<*>>` to require a serializer class without committing to the property type it handles. section 12.1.7

How Kotlin in Action, 2E covers it

How deep it goes
Defines syntax, inference, constraints, nullability, erasure, reification, and variance, with runnable collection and function examples.
Examples
Uses `List<String>`, `Map<String, Person>`, `slice<Char>`, constrained `max`, nullable `Processor`, and `filterIsInstance<String>`.
What it assumes
Builds from familiar Java-like generic syntax before extending it with Kotlin nullability, reification, and variance.
What you can do after
Apply it via Kotlin generic collections and functions, choosing explicit arguments, relying on inference, and respecting bounds and runtime erasure.
How it connects
Connects generic type parameters with type inference, upper bounds, nullability, type erasure, reified parameters, subtypes, and variance.

Also explained in

Compare how 5 books explain type argument →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Kotlin in Action, 2E. The section links point to the parts of the book it draws on.