What is the opt-in mechanism in Kotlin, and how do you consume an experimental API like ExperimentalCoroutinesApi?
answer
- @RequiresOptIn declares, @OptIn consumes
- @OptIn is local, non-propagating
- Three options: @OptIn / propagate / -opt-in flag
- ExperimentalCoroutinesApi is a coroutines marker
basics
~10 sSome Kotlin APIs are marked experimental and may change. The compiler warns or errors when you use them. To say 'I accept the risk', you add @OptIn(TheMarker::class) above your function or class.
solid answer
~40 sLibrary authors mark unstable APIs with a custom annotation defined via @RequiresOptIn. Using such an API produces a compiler warning or error unless you explicitly accept it. The simplest way is to annotate the using declaration with @OptIn(ExperimentalCoroutinesApi::class). @OptIn is local and non-propagating: it accepts the API only for that declaration and does NOT force callers of your code to opt in. ExperimentalCoroutinesApi is a real marker in kotlinx.coroutines protecting APIs like runningReduce-style flow operators or TestCoroutineScheduler internals. Alternatives to @OptIn: re-annotate your own declaration with the same marker (which propagates the requirement to your callers), or opt in project-wide with the -opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi compiler flag (configured via compilerOptions { optIn.add(...) } in Gradle).
code
kotlin · 6 linesimport kotlinx.coroutines.ExperimentalCoroutinesApi
@OptIn(ExperimentalCoroutinesApi::class)
fun consumeExperimentalCoroutineApi() {
// experimental coroutines API call goes here
}go deeper
Knows experimental APIs need @OptIn(Marker::class) to silence the compiler warning/error.
Distinguishes consuming (@OptIn) from declaring (@RequiresOptIn) and names the module-wide -opt-in flag.
Explains the propagation alternative and when @OptIn vs re-annotation vs flag is appropriate.
Frames opt-in as an API-evolution governance tool and reasons about its impact across a multi-module codebase.
## What problem does opt-in solve? Library authors sometimes want to ship an API that works but whose **signature or behavior might change** in a future release. They don't want callers to depend on it unknowingly. Kotlin's **opt-in requirement** mechanism lets an author flag such an API so that any use produces a compiler diagnostic until the caller explicitly acknowledges the risk. ## The two halves - **Declaring** the requirement: the author defines a marker annotation and tags it with `@RequiresOptIn`. Any API annotated with that marker becomes opt-in-required. - **Consuming** the API: the caller must do one of three things, or the compiler complains. ## Consuming options 1. **`@OptIn(Marker::class)`** on the using function/class/file. This is **local** and **non-propagating** — you accept the API here, and your own callers are unaffected. 2. **Propagate**: annotate your own declaration with the *same marker*. Now your declaration also requires opt-in, pushing the decision up to your callers. 3. **Module-wide**: pass `-opt-in=fully.qualified.Marker` to the compiler (Gradle: `kotlin { compilerOptions { optIn.add("...") } }`). Useful for accepting one marker across a whole module. ## `ExperimentalCoroutinesApi` example ```kotlin import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.flow @OptIn(ExperimentalCoroutinesApi::class) fun useExperimental() { // call into an API guarded by @ExperimentalCoroutinesApi } ``` `ExperimentalCoroutinesApi` is a marker annotation declared in kotlinx.coroutines; the library tags not-yet-stable coroutine/flow APIs with it. ## Key keywords `@RequiresOptIn` (declares), `@OptIn` (consumes locally), `-opt-in` / `optIn.add(...)` (module-wide), propagation by re-annotation.
- Does @OptIn force callers of your function to also opt in?No. @OptIn is non-propagating — it accepts the API only for the annotated declaration; callers are unaffected. To push the requirement up, you must re-annotate with the marker itself.
@OptIn is like signing a waiver before a risky activity — you accept the risk personally, but you don't sign on behalf of everyone after you.
saying these in an interview costs you the question
- Thinking @OptIn changes the experimental API's behavior rather than just silencing the diagnostic
- Claiming @OptIn propagates the requirement to callers
- Confusing @OptIn (consume) with @RequiresOptIn (declare)
- Believing experimental APIs are broken or unusable rather than just unstable