skip to content

Write a generic function whose type parameter must be both a `CharSequence` and `Comparable<T>`. Show exactly where the `where` clause goes in a function and in a class declaration.

level: middleimportance: must knowfreq 45%

answer

  1. Parameter brackets stay UNBOUNDED: `<T>`
  2. Function: after return type, before body
  3. Class: after supertypes, before `{`
  4. Comma-separated `T : X, T : Y`
  5. Can constrain several params: `T : A, U : B`

basics

~10 s

Declare the parameter as plain <T>, then after the return type (function) or the supertypes (class) add where T : CharSequence, T : Comparable<T> before the body.

solid answer

~50 s

For a **function**, the `where` clause comes after the parameter list and return type and before the body: `fun <T> f(x: T): R where T : CharSequence, T : Comparable<T> { ... }`. For a **class/interface**, it comes after the primary constructor and the supertype list and before the class body: `class Box<T>(val v: T) where T : CharSequence, T : Comparable<T> { ... }`. In both cases the bracketed parameter must be written **without** a bound (just `<T>`), because the bounds now live in `where`. Each constraint is a separate `T : SomeType` joined by commas, and you may constrain several different parameters in the same clause (`where T : A, U : B`). The clause expresses a conjunction; mixing it with a single inline bound on the same parameter is redundant and not how it is done.

code

kotlin · 13 lines
kotlin
fun <T> betweenInclusive(x: T, lo: T, hi: T): Boolean
    where T : CharSequence, T : Comparable<T> =
    x >= lo && x <= hi

class Sorted<T>(initial: List<T>)
    where T : CharSequence, T : Comparable<T> {
    val data = initial.sorted()
}

fun main() {
    println(betweenInclusive("m", "a", "z")) // true
    println(Sorted(listOf("b", "a")).data)     // [a, b]
}

go deeper

for a junior

Can copy the function form and put a comma-separated where after the return type.

for a middle

Places where correctly in both function and class forms and keeps the parameter unbounded in brackets.

for a senior

Knows the at-most-one-class rule and that several parameters can share one where.

for a principal

Explains the parser rationale for placement and the JVM single-inheritance constraint that limits class bounds.

## Function form The `where` clause attaches to the function **signature**, positioned after the return type and before the `=` or `{`: ```kotlin fun <T> clamp(value: T, lo: T, hi: T): T where T : CharSequence, T : Comparable<T> { return when { value < lo -> lo value > hi -> hi else -> value } } ``` Note: `T` in the brackets carries **no** bound — all bounds are in `where`. ## Class / interface form Here `where` comes after the primary constructor parameters and the supertype list, before the body: ```kotlin class SortedLabel<T>(val label: T) where T : CharSequence, T : Comparable<T> { fun isBlank() = label.isEmpty() } interface Repo<ID> where ID : Comparable<ID>, ID : java.io.Serializable ``` ## Rules to remember - The parameter in `<...>` must be **unbounded** when you use `where` for it; you do not also write `<T : X>`. - Constraints are **comma-separated**, each in the form `Param : Type`. - You can constrain **multiple** parameters at once: ```kotlin fun <T, U> copy(src: T, dst: U) where T : CharSequence, U : Appendable ``` - At most **one** of the constraints may be a class (non-interface) type; the rest must be interfaces, because Kotlin (like the JVM) has single inheritance of classes but multiple interfaces. - The clause is the same conjunction whether on a function, class, interface, or even a property's generic accessor receiver — semantics never change. ## Why placement matters Kotlin parses the supertype/return-type list first; the `where` keyword unambiguously begins the constraint block, which is why it must follow them and precede the body or `=`.

  • Can two of the `where` constraints both be (non-interface) classes?
    No. At most one constraint may be a class; the rest must be interfaces, mirroring single class inheritance on the JVM.
  • Is it legal to write `<T : CharSequence>` AND a `where T : Comparable<T>` together?
    It is technically rejected when you also put `T` in `where`; the idiomatic and required form is to leave `T` unbounded in brackets and place all bounds in `where`.

saying these in an interview costs you the question

  • Putting the bound in the brackets and in `where` for the same parameter
  • Placing `where` before the return type or before supertypes
  • Claiming you can list two classes (non-interfaces) as bounds
  • Forgetting that one `where` can constrain multiple parameters

context