skip to content

Contracts are unchecked. What goes wrong if a contract { } block lies, and how would you reason about that risk when shipping a library?

level: seniorimportance: should knowfreq 22%

answer

  1. Trusted, never verified
  2. False contract -> unsound smart cast -> NPE
  3. Delocalized: blows up at call site
  4. callsInPlace lie breaks definite assignment
  5. Test the guarantee, keep body in lockstep

basics

~20 s

The compiler believes whatever the contract says without checking it. If the contract is false, the compiler makes wrong smart casts, so code that looks safe can throw at runtime. You must make sure the body truly honors the contract.

solid answer

~40 s

Because the compiler does not verify a contract against the function body, a false contract is unsound: it tells the compiler to assume facts that may not hold, producing smart casts the compiler would otherwise reject. For example, declaring returns() implies (x != null) on a function that can return normally while x is still null lets callers dereference x without a null check, causing a NullPointerException at runtime even though there is no !! in sight. The same applies to callsInPlace: claiming EXACTLY_ONCE on a lambda that may not run breaks definite-assignment guarantees, leaving a val effectively uninitialized. When shipping a library, treat each contract as an API obligation: keep the body and contract in lockstep, cover the contract's guarantees with tests, and remember the DSL is still @ExperimentalContracts so signatures could shift.

code

kotlin · 6 lines
kotlin
@OptIn(ExperimentalContracts::class)
fun unsafe(x: Any?): Boolean {
    contract { returns(true) implies (x is String) }
    return true // body does not actually check x -> unsound
}
// caller: if (unsafe(42)) { (42 as String) }  // ClassCastException-style break

go deeper

for a junior

Understands the compiler trusts the contract and that a wrong one can crash at runtime.

for a middle

Can construct a concrete lying-contract example that produces an NPE with no !! at the call site.

for a senior

Explains delocalized unsoundness, both effect kinds failing, and a testing/review strategy to keep contracts honest.

for a principal

Frames contracts as an API obligation, weighs experimental-stability cost for consumers, and sets team guidance on when hand-rolled contracts are justified.

## The core fact: contracts are trusted, not verified The Kotlin compiler does **not** prove that your function body satisfies the `contract { }` you declared. It simply records the effects and applies them at every call site. This makes contracts a powerful but **unsound-by-construction** feature: correctness depends entirely on you. ## Failure mode 1: a lying returns/implies contract ```kotlin @OptIn(ExperimentalContracts::class) fun looksChecked(x: String?): Boolean { contract { returns(true) implies (x != null) } return true // BUG: returns true even when x is null } fun caller(x: String?) { if (looksChecked(x)) { println(x.length) // compiler smart-casts x to String -> NPE at runtime } } ``` The call site has no `!!` and looks perfectly safe, yet it throws. The bug is invisible at the call site and only the contract author can see it. ## Failure mode 2: a lying callsInPlace contract Claiming `callsInPlace(block, InvocationKind.EXACTLY_ONCE)` when the lambda might be skipped (e.g. guarded by a condition) lets a caller initialize a `val` inside it. If the block never runs, the `val` is read uninitialized — the compiler's definite-assignment guarantee is violated. ## Why this matters more than a normal bug - The unsafety is **delocalized**: it surfaces at call sites the author never sees. - It **defeats** the very safety net (null-safety, definite assignment) that Kotlin users rely on. - There is **no compiler diagnostic** — `./gradlew build` stays green. ## Reasoning about it when shipping - **Treat the contract as part of the public contract of the API** — changing the body must keep honoring it. - **Test the guarantee**, not just the return value: assert that, whenever the function returns the contracted result, the implied condition truly holds. - **Prefer the stdlib's existing contracted helpers** (`require`, `requireNotNull`, `isNullOrEmpty`) over hand-rolled ones when possible. - **Account for experimental status**: `@ExperimentalContracts` means the surface can change; opting in is a stability decision for your library's consumers. - **Keep contracts minimal and obviously true** — the simplest contract that matches the simplest control flow is the safest. ## Mental model A contract is a `@Suppress` for the compiler's reasoning combined with a promise. If the promise is false, you have effectively suppressed a real diagnostic.

  • Does ./gradlew build or detekt catch a false contract?
    No. The compiler trusts the contract and emits no diagnostic; standard static analysis won't flag the lie. Only tests or review catch it.
  • How can a false callsInPlace contract corrupt state?
    Claiming EXACTLY_ONCE lets a caller initialize a val in the lambda; if the lambda is skipped, that val is read uninitialized despite the compiler thinking it is assigned.

Like a building inspector stamping 'approved' without entering the building — every tenant trusts the stamp, and the collapse happens far from the inspector.

saying these in an interview costs you the question

  • Assuming the compiler validates the body against the contract
  • Adding a broad contract 'to be safe' without matching control flow
  • Not testing that the implied condition actually holds
  • Ignoring the experimental/opt-in stability cost for library consumers
  • Treating contract bugs as ordinary local bugs

context