Write a custom validation helper that smart-casts its argument to non-null after the call. Explain each part of the contract DSL you use.
answer
- contract { } must be the FIRST statement
- returns() / returns(true|false|null) implies (cond)
- Conditions limited to null checks, type checks, booleans
- @OptIn(ExperimentalContracts::class)
- Body must actually enforce the claim (unchecked)
basics
~20 sAdd a contract { } block as the first line of the function. Inside, write returns() implies (arg != null). That tells the compiler that whenever the function returns normally, the argument was not null, so callers can use it as non-null.
solid answer
~40 sUse the experimental kotlin.contracts DSL. Make the function inline (required for contracts that reference a lambda; for a plain value predicate it still must be a top-level/member function with the contract as the first statement). Write contract { returns() implies (input != null) } as the very first statement, before any other code. returns() is a ReturnsEffect meaning 'returned without throwing'; implies takes a boolean condition over the parameters that holds given that effect — supported forms include x != null, x == null, x is T, x !is T, and true/false (with returns(true)/returns(false)). The body must actually enforce it (e.g. throw on null), because contracts are unchecked promises — the compiler trusts them. Then opt in with @OptIn(ExperimentalContracts::class) or @ExperimentalContracts. Misusing a contract that the body doesn't honor produces unsound smart casts.
code
kotlin · 8 linesimport kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
@OptIn(ExperimentalContracts::class)
fun requireValid(value: String?) {
contract { returns() implies (value != null) }
require(value != null && value.isNotBlank()) { "invalid" }
}go deeper
Can copy the pattern contract { returns() implies (x != null) } and knows it goes first.
Explains returns()/returns(true) and the limited set of allowed conditions, plus the opt-in.
Stresses that contracts are unchecked promises and the body must enforce them to avoid unsound smart casts.
Weighs whether to expose contract-bearing helpers as API, the experimental-API stability cost, and team conventions around them.
## Goal Write `requireValid(x)` so that after it returns, `x` is smart-cast to non-null. ```kotlin import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract @OptIn(ExperimentalContracts::class) fun requireValid(value: String?) { contract { returns() implies (value != null) } require(!value.isNullOrBlank()) { "value must be non-blank" } } fun use(s: String?) { requireValid(s) println(s.length) // s smart-cast to String } ``` ## The DSL piece by piece - **`kotlin.contracts.contract { ... }`** — the entry point. It is an *intrinsic*: it produces no runtime code; it exists only to inform the compiler. It **must be the first statement** of the function body. - **`returns()`** — a `ReturnsEffect`. The empty parentheses mean "the function returned normally" (no exception). Variants: - `returns(true)` / `returns(false)` — for functions returning `Boolean`, condition applies only when that exact value is returned. - `returns(null)` — applies when `null` is returned. - **`implies (condition)`** — attaches a condition that is guaranteed true *when* that effect happens. Allowed conditions are limited to: - null checks: `value != null`, `value == null` - type checks: `value is Foo`, `value !is Foo` - boolean parameters / negations of the above, combined with `&&`, `||`, `!`. - **Parameters only**: the condition may reference the function's **parameters** (and the receiver), not arbitrary locals. ## Required opt-in Contracts are still an **experimental** API. Annotate with `@OptIn(ExperimentalContracts::class)` (or `@ExperimentalContracts`) or the compiler rejects the `contract` call. ## Why the body must honor it A contract is an **unchecked promise**. The compiler does *not* verify your body actually enforces it. If you write `implies (value != null)` but never throw on null, you create an **unsound smart cast** that can cause a `NullPointerException` at a usage site the compiler believed was safe. Always make the body match the claim. ## returns(Boolean) form for predicates For a function returning Boolean you can smart-cast on a *specific* result: ```kotlin @OptIn(ExperimentalContracts::class) fun isNonEmpty(s: String?): Boolean { contract { returns(true) implies (s != null) } return s != null && s.isNotEmpty() } ``` Now `if (isNonEmpty(x)) { x.length }` smart-casts `x` inside the `true` branch.
- What conditions can appear after 'implies'?Only null checks (x != null/== null), type checks (x is T / x !is T), and boolean-valued combinations — referencing parameters/receiver, not arbitrary locals.
- What happens if your body doesn't actually enforce the contract?Nothing at compile time — contracts are unchecked. You get an unsound smart cast that can blow up with an NPE/ClassCastException at the call site the compiler trusted.
saying these in an interview costs you the question
- Putting contract { } anywhere other than the first statement
- Referencing local variables instead of parameters in the implies condition
- Forgetting the @OptIn / ExperimentalContracts opt-in
- Believing the compiler verifies the body matches the contract
- Writing arbitrary expressions (e.g., value.length > 0) in implies