Generics

Kotlin is a modern, concise language whose generics let you write one class or function that works safely with any type — the same machinery behind List , Map , and Set .

Learn Generics in our free Kotlin course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.

Part of the free Kotlin course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

By the end of this lesson you'll write generic classes and functions, add type constraints, and understand variance at a high level.

What You'll Learn in This Lesson

1️⃣ Generic Classes and Functions

A type parameter in angle brackets, like , is a placeholder for a real type supplied when the generic is used. The compiler tracks it, so a Box Int returns an Int — no casts needed.

Notice the compiler inferred T from the arguments — you rarely have to write the type explicitly.

2️⃣ Constraints and a Generic Stack

An upper bound like restricts T to types you can compare, unlocking operators like . A generic Stack T shows how one reusable type works for strings, numbers, or anything else.

The same maxOf compared both numbers and strings, because both are Comparable . Write it once, reuse it everywhere.

Your turn. Replace the TODO , then run and compare.

Write generic functions with one and two type parameters and call them with different types.

📋 Quick Reference — Generics

Practice quiz

What does a type parameter like <T> represent?

  • A fixed type that is always Int
  • A placeholder for a real type supplied per use
  • A runtime null value
  • A reserved keyword for objects

Answer: A placeholder for a real type supplied per use. <T> is a placeholder filled in with a real type when the generic is used.

How is a generic function declared in Kotlin?

  • fun firstOf<T>(...)
  • fun firstOf(...)<T>
  • fun <T> firstOf(...)
  • generic fun firstOf(...)

Answer: fun <T> firstOf(...). The type parameter comes before the function name: fun <T> firstOf(...).

In Box(42), how does the compiler know T is Int?

  • By type inference from the argument
  • It defaults to Any
  • You must always write Box<Int>
  • It guesses randomly

Answer: By type inference from the argument. The compiler infers T = Int from the constructor argument 42.

What does the upper bound <T : Comparable<T>> guarantee?

  • T is always a String
  • T can be null
  • Values of T can be compared with < and >
  • T has no methods

Answer: Values of T can be compared with < and >. The bound guarantees T implements Comparable, so comparison operators work.

Which naming convention is typically used for a map's key and value parameters?

  • X and Y
  • A and B
  • T and E
  • K and V

Answer: K and V. K and V are the conventional names for key and value type parameters.

What is the main benefit of generics over using Any?

  • They run faster at startup
  • They preserve compile-time type safety without casts
  • They allow null everywhere
  • They remove the need for functions

Answer: They preserve compile-time type safety without casts. Generics keep full type safety, so no casting is needed unlike with Any.

How many type parameters can a generic function declare?

  • Exactly one
  • At most two
  • One or more, such as <K, V>
  • None

Answer: One or more, such as <K, V>. A function can declare multiple type parameters, e.g. fun <K, V> pairUp(...).

Why is Kotlin's List declared as List<out E>?

  • To make it mutable
  • To make it covariant (a producer)
  • To forbid reading elements
  • To require explicit casts

Answer: To make it covariant (a producer). out makes List covariant, so a List<String> works where List<Any> is wanted.

When the compiler can't infer T, how do you supply it?

  • Use Any instead
  • Cast the result
  • Add a semicolon
  • Provide it explicitly, like Box<String>("hi")

Answer: Provide it explicitly, like Box<String>("hi"). Supply the type argument explicitly when inference fails.

What does 'in T' (contravariance) mark a type parameter as?

  • A consumer position
  • A producer position
  • An invariant position
  • A nullable position

Answer: A consumer position. in marks a consumer position — the type only accepts T as input.