Write a custom inline function that wraps a block and lets callers initialize a `val` from inside its lambda. What is the exact `contract { }` declaration, what opt-in is needed, and what placement rules apply?
answer
- contract { } must be FIRST statement
- callsInPlace(block, EXACTLY_ONCE) on a param
- @OptIn(ExperimentalContracts::class)
- must call block exactly once at runtime — not verified
- imports from kotlin.contracts
basics
~10 sPut a contract as the very first statement of the function and call callsInPlace(block, EXACTLY_ONCE). Mark it with the experimental contracts opt-in. Then callers can set a val inside the lambda.
solid answer
~40 sAdd a `contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }` as the **first statement** of the function body (nothing may precede it, not even a log line). The `block` you name must be a lambda parameter of that function. Because authoring contracts is still experimental, annotate the function with `@OptIn(ExperimentalContracts::class)` (or propagate `@ExperimentalContracts`). The function does not strictly need `inline`, but in practice you make scope-style helpers `inline` so the lambda can use non-local returns and so there's no allocation. Crucially you must actually honor the contract at runtime — call `block()` exactly once — otherwise you've lied to the compiler and risk uninitialized reads or NPEs at runtime. Imports come from `kotlin.contracts`: `contract`, `InvocationKind`, `ExperimentalContracts`.
code
kotlin · 13 linesimport kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
@OptIn(ExperimentalContracts::class)
inline fun <T, R> withResource(resource: T, block: (T) -> R): R {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
return block(resource)
}
val parsed: Int
withResource("42") { s -> parsed = s.toInt() }
println(parsed)go deeper
Can copy the stdlib pattern but may miss the first-statement rule or the opt-in.
Writes the function correctly with opt-in, first-statement placement, and references the lambda parameter.
Stresses that the contract is trusted not verified, and shows how lying about the count breaks caller soundness; chooses @OptIn vs propagating @ExperimentalContracts deliberately.
Weighs API-stability implications of shipping contracts, the experimental marker leaking to consumers, and how to test that the runtime honors the declared kind.
## Goal Let callers do: ```kotlin val result: String runOnce { result = compute() } println(result) ``` ## The function ```kotlin import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract @OptIn(ExperimentalContracts::class) inline fun <R> runOnce(block: () -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block() } ``` ## Rules you must follow 1. **First statement**: the `contract { }` call must be the *very first* statement of the function body. Putting any code before it is a compile error (`Contract should be the first statement`). 2. **Block parameter identity**: the first argument to `callsInPlace` must be a *parameter* of the function (the lambda), referenced directly — not a local val, not a property. 3. **Opt-in**: contract authoring is behind `@ExperimentalContracts`. Use `@OptIn(ExperimentalContracts::class)` on the function (or annotate the function itself `@ExperimentalContracts`, which then forces callers to opt in — usually you don't want that, so prefer `@OptIn`). 4. **Honor it at runtime**: you promised EXACTLY_ONCE, so the body must call `block()` exactly once on every path. The compiler does **not** verify this — it trusts you. Calling it zero times, twice, or storing it for later is undefined behavior from the analysis's view and can yield uninitialized state. 5. **inline is optional but idiomatic**: `inline` lets the lambda perform non-local `return`, avoids a lambda allocation, and matches stdlib style. The contract itself works without inline. ## Common mistakes ```kotlin @OptIn(ExperimentalContracts::class) inline fun bad(block: () -> Unit) { log.debug("start") // ERROR: must be first contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } block() } ``` and lying about the count: ```kotlin @OptIn(ExperimentalContracts::class) inline fun liar(block: () -> Unit) { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } if (Random.nextBoolean()) block() // BUG: may run 0 times, breaks the promise } ``` A caller's `val` could then be read while uninitialized. ## Why the compiler trusts you Contracts are a *promise*, not a proof. They extend flow analysis based on your declaration. This is why the feature is still experimental for authors: a wrong contract silently corrupts the caller's analysis.
- What error do you get if the contract is not the first statement?A compile error such as 'Contract should be the first statement'; the contract call must precede all other code in the body.
- Does the compiler check that you really call block exactly once?No. Contracts are trusted, not verified. If you violate the declared kind the caller's flow analysis becomes unsound, which can cause uninitialized reads or NPEs at runtime.
saying these in an interview costs you the question
- Puts logging or other code before the contract block
- Passes a local variable instead of the lambda parameter to callsInPlace
- Forgets the experimental opt-in entirely
- Claims the compiler verifies the invocation count
- Insists inline is mandatory for callsInPlace to work