skip to content

Why does the Kotlin compiler emit a 'Expected classes are in Beta' warning, and what are the practical risks and alternatives when using `expect class`?

level: middleimportance: should knowfreq 35%

answer

  1. Beta = warning, not error; behavior may change
  2. expect fun/val stable; expect class still Beta
  3. @OptIn(ExperimentalMultiplatform::class) silences it
  4. libraries: prefer actual typealias / interface+factory
  5. apps: low risk, fix in one place on upgrade

basics

~20 s

Expected classes are still marked Beta, so Kotlin warns you their behavior may change in future versions. For stable public APIs, many teams prefer matching a platform type with actual typealias or using interface + factory instead, reserving expect class for app-internal code.

solid answer

~50 s

When you declare an `expect class`/`expect object`, the Kotlin compiler emits a warning that **expected classes are in Beta** and may change. This reflects that, unlike `expect fun`/`expect val` (stable), expected *classes* carry edge cases (member matching subtleties, supertype resolution, evolving rules) the team is still hardening, so source/behavior compatibility across compiler versions is not fully guaranteed. You can opt in with `@OptIn(ExperimentalMultiplatform::class)` or suppress via the compiler flag to silence it, but the pragmatic advice is: for **stable, published library APIs**, prefer `actual typealias` to map the expect onto an existing platform type, or model the seam as a common **interface** plus a platform-specific factory (`expect fun create(): MyApi`). Reserve `expect class` for application-internal seams where you control all callers and can adapt to changes. Functions and properties via expect/actual remain the lower-risk choice.

go deeper

for a junior

Recognizes there is a Beta warning and that it does not stop the code from compiling.

for a middle

Explains why classes (vs functions) are Beta and that the contract may change between compiler versions.

for a senior

Weighs the library-vs-app risk and names alternatives (typealias, interface+factory) and how to opt in.

for a principal

Sets a team policy: where expect class is acceptable, where to prefer stable seams, and how to insulate a public API from Beta-feature churn.

## The warning Declaring an expected class triggers a compiler diagnostic along the lines of *“Expected classes are in Beta. Their behavior and/or interface may be changed in future versions.”* It is a **warning, not an error** — your code compiles and runs. ## Why Beta? Expected **functions and properties** have been stable for a long time. Expected **classes/objects** involve trickier semantics: - member-by-member matching including constructors, supertypes, nested classes; - actualization-by-inheritance and via typealias; - interaction with sealed/enum/data/value classes; - how added members on the actual are governed. Because these rules are still being refined, the Kotlin team labels the feature Beta so the contract isn't frozen. ## Practical risks - A future compiler version could tighten or change matching rules, requiring small code changes. - For **libraries**, this is a real concern: your published API shape is tied to a Beta feature. For **apps**, you upgrade Kotlin and fix any breakage in one place, so the risk is low. ## Silencing the warning ```kotlin @OptIn(ExperimentalMultiplatform::class) expect class Foo() ``` or opt in project-wide via the compiler argument. Suppressing the warning does **not** change the Beta status — it just acknowledges it. ## Lower-risk alternatives 1. **actual typealias**: if a suitable platform type already exists, map to it instead of writing a fresh actual class. ```kotlin // commonMain expect class AtomicInt // jvmMain actual typealias AtomicInt = java.util.concurrent.atomic.AtomicInteger ``` 2. **Common interface + expect factory function** (functions are stable): ```kotlin interface Storage { fun save(k: String, v: String) } expect fun createStorage(): Storage ``` 3. **Keep expect class internal** to the app where you own all call sites. ## When expect class is still the right call When no platform type fits, you need a concrete shared type (not just an interface — e.g. for value semantics or to avoid an extra allocation), and you control the consumers. The Beta warning is then an acceptable trade-off.

  • Does suppressing the Beta warning make the feature stable?
    No. Opting in only stops the diagnostic; the feature's contract is still Beta and could change in a future Kotlin release.
  • For a published multiplatform library, what would you reach for instead of expect class?
    An actual typealias onto an existing platform type, or a common interface with an expect factory function, since those carry less compatibility risk.

saying these in an interview costs you the question

  • Treating the Beta warning as a compile error that must be 'fixed' by abandoning KMP
  • Believing @OptIn makes expected classes stable
  • Recommending expect class for every library seam without weighing typealias/interface
  • Confusing expect class Beta status with expect fun, which is stable
  • Claiming the warning means runtime instability

context