In Kotlin generics, what does the `where` clause do, and how does it differ from writing an upper bound inline like `<T : CharSequence>`?
answer
- Inline brackets allow only ONE bound
- `where` = multiple upper bounds, all required (AND)
- `where` sits after return type, before body
- Comma-separated `T : X, T : Y`
- Compile-time only, erased at runtime
basics
~20 sThe where clause lets a type parameter require more than one constraint at once. Inline syntax like <T : CharSequence> can only state one bound, so when you need two or more you move them into where.
solid answer
~40 sAn upper bound restricts which types can be substituted for a type parameter. Inline angle-bracket syntax (`fun <T : CharSequence> f(t: T)`) supports exactly one bound per parameter. When a parameter must satisfy several bounds at once, you list the parameter without a bound in the brackets and add a `where` clause after the signature: `fun <T> f(t: T) where T : CharSequence, T : Comparable<T>`. Every comma-separated constraint must hold simultaneously (logical AND), so only types that are both a `CharSequence` and `Comparable<T>` are accepted. The `where` clause goes before the function body / class body. It is purely a compile-time constraint with no runtime cost; bounds are erased like all generic type information.
code
kotlin · 8 lines// Single bound (inline)
fun <T : CharSequence> len(t: T) = t.length
// Multiple bounds (where) — T must be BOTH
fun <T> pick(a: T, b: T): T where T : CharSequence, T : Comparable<T> =
if (a >= b) a else b
val r = pick("apple", "pear") // String is CharSequence + Comparablego deeper
Knows where allows more than one bound and that inline allows only one.
States the AND semantics and correct placement after the return type, before the body.
Connects it to type erasure and explains there is no runtime cost or runtime inspectability.
Frames where as the only way to express a conjunction of bounds and discusses API design trade-offs of demanding several capabilities from one parameter.
## What an upper bound is A generic type parameter (the `T` in `<T>`) is a placeholder for a real type chosen by the caller. An **upper bound** says "the type filling in for `T` must be a subtype of X." The default upper bound is `Any?` (anything, nullable included). ## Single bound: inline syntax For one bound you write it in the angle brackets: ```kotlin fun <T : CharSequence> firstChar(t: T): Char = t[0] ``` Here `T` must be a `CharSequence`, so `String` and `StringBuilder` work but `Int` does not. ## Why `where` exists The inline form allows **only one** bound per parameter. The `where` clause removes that limit: it lets you impose **multiple** upper bounds on the same parameter, all of which must hold at the same time (a logical AND). ```kotlin fun <T> maxLabel(items: List<T>): T where T : CharSequence, T : Comparable<T> = items.max() ``` `T` must be **both** a `CharSequence` **and** `Comparable<T>`. `String` satisfies both, so `String` is a valid `T`. ## Syntax placement - The parameter is declared **without** a bound inside the brackets: `<T>`. - The `where` clause comes **after** the return type (for functions) or the supertype list (for classes), and **before** the body. - Constraints are comma-separated: `where T : A, T : B`. ## Key facts - It is a **compile-time** check only. Generics are erased at runtime, so the bounds add no runtime cost and cannot be inspected via reflection on the type variable. - Each constraint is an independent `T : Something`; you cannot write `T : A & B` inline. - You can constrain multiple parameters in one `where`: `where T : A, U : B`.
- Can you put two bounds inline, like `<T : A, T : B>`?No. Inline syntax permits only one bound per parameter; repeating `T` in the brackets is a compile error. Multiple bounds require the `where` clause.
- Do the `where` constraints combine as AND or OR?AND. The substituted type must satisfy every listed constraint simultaneously.
Inline <T : X> is a single entry requirement; the where clause is a checklist where every box must be ticked.
saying these in an interview costs you the question
- Claiming you can write multiple inline bounds with commas inside the brackets
- Saying the constraints are an OR (any one suffices)
- Thinking `where` adds runtime checks or runtime cost
- Confusing `where` (upper bounds) with variance (`in`/`out`)