When should you use `T & Any` versus just bounding the type parameter with `T : Any`? How do they differ?
answer
- T : Any constrains all callers; T & Any constrains one position
- Bound rejects List<String?>; & Any still allows it
- Use & Any when you can't re-bound (interop/override)
- Redundant (& warning) if bound already T : Any
- Bound = global; & Any = local guarantee
basics
~20 sT : Any forces every use of T to be non-null for all callers. T & Any keeps T able to be nullable but marks one specific spot (a parameter, return, or local) as non-null.
solid answer
~50 s`T : Any` is an **upper bound** on the type parameter: it constrains the whole declaration so callers can only substitute non-null types, and every occurrence of `T` is non-null. `T & Any` leaves `T` with its (nullable) bound but applies non-nullability **at one position** — a parameter, return type, or local. Use `T : Any` when the entire generic abstraction should reject nullable instantiations (you control the API and nullability never makes sense). Use `T & Any` when `T` must stay general — for example because you're overriding a Java method or implementing an interface whose `T` you cannot re-bound, but a specific position is non-null. The classic case is interop: you can't change the inherited `T`'s bound, so you can't add `T : Any`, but you can write `T & Any` on your override's signature. They are not interchangeable: `T : Any` changes call-site flexibility; `T & Any` is a local guarantee.
go deeper
Knows both exist and that one is a bound and one is a position-level type.
Correctly chooses between them and explains that T : Any forbids List<String?> while T & Any does not.
Explains the interop/inheritance scenario where re-bounding is impossible so & Any is the only option, and notes the redundancy warning.
Reasons about API design trade-offs: constraining callers vs preserving generality, and how each choice ripples through a public library's variance and source compatibility.
## Two different tools ### `T : Any` — a bound on the parameter ```kotlin fun <T : Any> requireFirst(list: List<T>): T = list.first() ``` Here `T` can never be nullable. Callers **cannot** pass `List<String?>` — the bound rejects it. Every mention of `T` in the function is non-null. This is a global constraint on the abstraction. ### `T & Any` — a definitely-non-null type at one position ```kotlin fun <T> firstOrThrow(list: List<T>): T & Any = list.firstOrNull() ?: error("empty") ``` Here `T` is still free to be `String?` (`List<String?>` is allowed). Only the **return position** is promised non-null. The same `T` may appear nullable elsewhere. ## When each fits | Situation | Prefer | |---|---| | You own the API and nullable `T` is meaningless | `T : Any` (cleanest, enforced at every use) | | You override a Java/3rd-party method whose `T` you can't re-bound | `T & Any` (only legal option) | | `T` legitimately may be nullable but one result must be non-null | `T & Any` | | You want call-site to forbid `List<String?>` | `T : Any` | ## Key insight `T & Any` is the only choice when you **cannot** change the bound — most often at an inheritance/interop boundary. If you control the bound and want it everywhere, `T : Any` is clearer and constrains callers too. Writing `T & Any` where the bound is already `T : Any` is redundant and warns. ## Related operators/keywords - upper bound (`:` in `<T : Any>`) — restricts substitution. - `&` intersection — the definitely-non-null form. - `where` clause — for multiple bounds, still about constraining `T` globally, unlike `& Any`.
- Can you add `T : Any` to an override of a Java generic method to get the same effect?No. The type parameter and its bound are fixed by the supertype/interface; you must keep a compatible `T`. You can only refine the position with `T & Any`.
- If a function has `<T : Any>`, is `T & Any` ever useful inside it?No — `T` is already non-null, so `T & Any` is redundant and the compiler warns. Just use `T`.
saying these in an interview costs you the question
- Treating `T : Any` and `T & Any` as synonyms
- Adding `T : Any` to an override and breaking the signature compatibility
- Not knowing that `T : Any` forbids nullable instantiations at call sites
- Using `T & Any` everywhere as a 'safer default' when re-bounding would be cleaner