Contrast propagating an opt-in requirement (re-annotating with the marker) versus using @OptIn locally. When would you choose each?
answer
- Propagate = re-annotate with the marker
- @OptIn = contain, non-propagating
- Decision: does instability leak past your boundary?
- @OptIn on a leaky API hides risk from callers
- @file:OptIn for file-level scope
basics
~10 sRe-annotating with the marker passes the 'please opt in' requirement on to whoever calls your code. Using @OptIn stops the requirement at your code — your callers don't have to do anything.
solid answer
~50 sIf you re-annotate your own declaration with the experimental marker (e.g. @ExperimentalCoroutinesApi), you PROPAGATE the requirement: your declaration now also demands opt-in, and your callers face the same diagnostic. This is right when your API genuinely exposes the experimental surface to callers — instability leaks through, so the warning should too. Using @OptIn(Marker::class) instead CONTAINS the experimental usage: you accept the risk internally and present a stable façade to callers. Choose @OptIn when you fully encapsulate the experimental API (it doesn't appear in your public signatures or behavior contract). Choose propagation when the experimental type/behavior is part of what you hand back, so callers must consciously accept it too. Overusing @OptIn on leaky APIs hides instability from people who'll be bitten by it; overusing propagation spams diagnostics onto callers who don't actually touch anything unstable.
code
kotlin · 7 lines// Contain: stable façade, callers unaffected
@OptIn(ExperimentalCoroutinesApi::class)
fun safeCount(): Int = experimentalCount()
// Propagate: experimental type leaks, so requirement leaks too
@ExperimentalCoroutinesApi
fun rawExperimental(): ExperimentalCoroutineDispatcher = buildIt()go deeper
May only know @OptIn exists; likely unaware propagation is a distinct strategy.
Knows both mechanisms and that re-annotating propagates, but may not articulate when each is correct.
Applies the 'does instability leak past my boundary' rule and identifies @OptIn-on-leaky-API as the key anti-pattern.
Sets team-wide conventions for façade vs propagation and reasons about stability contracts across module/public-API boundaries.
## The two strategies When your code uses an opt-in-required API, you must resolve the diagnostic. Two structurally different choices: ### 1. Contain with `@OptIn` ```kotlin @OptIn(ExperimentalCoroutinesApi::class) fun stableWrapper(): Int { // call experimental API, but return a plain Int return computeStably() } ``` - **Non-propagating.** Callers of `stableWrapper` see no opt-in requirement. - Correct **only if** the experimental surface does not leak — no experimental type appears in the signature, and you're not forwarding unstable behavioral guarantees. ### 2. Propagate by re-annotation ```kotlin @ExperimentalCoroutinesApi fun leakyWrapper(): SomeExperimentalType { return getExperimentalValue() } ``` - Your declaration is now itself opt-in-required. - Callers must `@OptIn(ExperimentalCoroutinesApi::class)` (or propagate again). - Correct when the **experimental surface is part of your contract** — the unstable type or behavior is visible to callers. ## Decision rule Ask: *does the instability leak past my API boundary?* - **No** (fully encapsulated) → `@OptIn`. Present a stable façade. - **Yes** (experimental type returned/accepted, or unstable semantics forwarded) → **propagate**. Don't lie about stability. ## Anti-patterns - **@OptIn on a leaky API**: you silence the diagnostic but your callers now depend on something unstable *without knowing*. When it changes, they break with no warning. This is the dangerous mistake. - **Propagation when fully contained**: you needlessly force callers to opt in, polluting their code with markers for instability they never see. ## Granularity note `@OptIn` can be applied at file level (`@file:OptIn(...)`), class, function, or property scope — pick the **narrowest** scope that covers the use, to keep the acknowledgement greppable and intentional.
- Why is using @OptIn on an API that returns an experimental type considered a mistake?Because the instability still reaches callers through your return type, but you've hidden the opt-in signal — they unknowingly depend on something that may change and will break silently. Propagation keeps the warning honest.
Propagation is forwarding a 'handle with care' label on a package you pass along; @OptIn is repackaging the contents into a sturdy box so the next person never sees the fragile original.
saying these in an interview costs you the question
- Treating @OptIn and propagation as interchangeable
- Using @OptIn to hide an experimental type that appears in a public signature
- Propagating markers even when the API is fully encapsulated
- Not knowing @OptIn can scope to file/class/function/property
- Claiming @OptIn affects callers