Kotlin 2.3 for Android: Name-Based Destructuring, KMP and Interview Questions 2026
Kotlin 2.3 interview questions covering name-based destructuring, Kotlin Multiplatform, context parameters, coroutines and Flow. Prepare for Android developer interviews in 2026 with real-world code examples.

Kotlin 2.3 interview questions now rank among the most searched topics for Android developer roles in 2026. With name-based destructuring declarations, stabilized context parameters, and a mature Kotlin Multiplatform ecosystem, interviewers expect candidates to demonstrate fluency in these features.
Kotlin 2.3.20, released March 2026, introduces name-based destructuring declarations, overload resolution changes for context parameters, and improved KMP interop with C and TypeScript. These features appear frequently in senior Android interviews.
Name-Based Destructuring: The Most Common Kotlin 2.3 Interview Question
Before Kotlin 2.3, destructuring declarations relied on position-based componentN() functions. This created a well-known pitfall: swapping property order in a data class silently broke existing destructuring sites.
The classic interview question presents this scenario:
data class User(val username: String, val email: String)
fun main() {
val user = User("alice", "alice@example.com")
// Position-based: order matters, not names
val (email, username) = user
println(email) // Prints "alice" -- wrong!
println(username) // Prints "alice@example.com" -- wrong!
}Kotlin 2.3.20 solves this with name-based destructuring. Three compiler modes control the behavior:
kotlin {
compilerOptions {
// Mode 1: Explicit syntax only
freeCompilerArgs.add("-Xname-based-destructuring=only-syntax")
// Mode 2: Warns on name mismatch
// freeCompilerArgs.add("-Xname-based-destructuring=name-mismatch")
// Mode 3: Full name-based by default
// freeCompilerArgs.add("-Xname-based-destructuring=complete")
}
}With complete mode, parentheses use name-based matching, and square brackets preserve position-based behavior:
data class User(val username: String, val email: String)
fun main() {
val user = User("alice", "alice@example.com")
// Name-based: matches by property name
val (email, username) = user
println(email) // "alice@example.com" -- correct
println(username) // "alice" -- correct
// Position-based: square brackets preserve old behavior
val [first, second] = user
println(first) // "alice" (component1)
println(second) // "alice@example.com" (component2)
}A strong answer in an interview explains all three modes and identifies when each applies: only-syntax for gradual migration, name-mismatch for catching bugs in existing code, and complete for new projects.
Kotlin Multiplatform Interview Questions for Android Developers
KMP has moved past the experimental phase. Google officially supports it for sharing business logic between Android and iOS, and most new multi-platform projects adopt a shared-core architecture by default.
A typical interview question asks: "How would you structure a KMP module for shared networking?"
import io.ktor.client.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
@Serializable
data class UserProfile(
val id: String,
val displayName: String,
val avatarUrl: String?
)
// Expect/actual pattern for platform-specific HTTP engine
expect fun createHttpClient(): HttpClient
class ApiClient {
private val client = createHttpClient()
private val json = Json { ignoreUnknownKeys = true }
// Suspend function shared across Android and iOS
suspend fun fetchProfile(userId: String): UserProfile {
val response = client.get("https://api.example.com/users/$userId")
return json.decodeFromString(response.bodyAsText())
}
}import io.ktor.client.*
import io.ktor.client.engine.okhttp.*
// Android uses OkHttp engine
actual fun createHttpClient(): HttpClient = HttpClient(OkHttp) {
engine {
config {
retryOnConnectionFailure(true)
}
}
}Interviewers evaluate whether the candidate understands the expect/actual mechanism, platform-specific dependencies, and the boundary between shared and platform code.
Another frequent question covers Swift Export, which has evolved significantly in 2026. Kotlin suspend functions now map directly to Swift async/await, and sealed classes map to Swift enums with associated values.
Context Parameters and Overload Resolution Changes
Context parameters replace the deprecated context receivers API. Kotlin 2.3.20 introduced a breaking change in overload resolution: declarations with context parameters are no longer treated as more specific than those without.
class Logger {
fun info(msg: String) = println("INFO: $msg")
}
class TransactionScope {
fun execute(block: () -> Unit) = block()
}
// Function with context parameter
context(logger: Logger)
fun saveUser(id: Int) {
logger.info("Saving user $id")
}
// Overload without context -- now ambiguous in 2.3.20
fun saveUser(id: Int) {
println("Saving user $id (no logger)")
}
fun main() {
val logger = Logger()
// This now produces an ambiguity error in Kotlin 2.3.20
// context(logger) { saveUser(1) }
// Fix: rename or qualify the context-aware variant
}Interviewers use this topic to assess awareness of breaking changes and migration strategies. The key takeaway: relying on implicit context parameter resolution to shadow non-contextual overloads no longer works.
Coroutines and Flow: Still the Top Android Interview Topic
Despite Kotlin 2.3 introducing new features, coroutines and Flow remain the most tested area. Interview questions typically probe the difference between cold and hot flows, structured concurrency, and cancellation.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
// Cold Flow: emits only when collected
fun userUpdates(): Flow<String> = flow {
println("Flow started") // Runs per collector
emit("User logged in")
delay(1000)
emit("User updated profile")
}
// Hot Flow: emits independently of collectors
class UserRepository {
// StateFlow holds the latest value
private val _state = MutableStateFlow("idle")
val state: StateFlow<String> = _state.asStateFlow()
// SharedFlow broadcasts to multiple collectors
private val _events = MutableSharedFlow<String>()
val events: SharedFlow<String> = _events.asSharedFlow()
suspend fun login() {
_state.value = "loading"
delay(500)
_state.value = "authenticated"
_events.emit("login_success")
}
}A follow-up question often asks about collecting flows safely in Android:
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
class UserViewModel(private val repo: UserRepository) : ViewModel() {
// Expose state to Compose UI
val uiState: StateFlow<String> = repo.state
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = "idle"
)
init {
// Collect events safely within ViewModel scope
viewModelScope.launch {
repo.events.collect { event ->
// Handle one-time events
println("Event received: $event")
}
}
}
}The WhileSubscribed(5000) strategy keeps the upstream active for 5 seconds after the last subscriber disappears, preventing unnecessary restarts during configuration changes like screen rotation.
Ready to ace your Android interviews?
Practice with our interactive simulators, flashcards, and technical tests.
Sealed Classes and Exhaustive When: Pattern Matching in Interviews
Sealed classes appear in nearly every Android interview. The question typically asks candidates to model a UI state:
sealed interface UiState<out T> {
data object Loading : UiState<Nothing>
data class Success<T>(val data: T) : UiState<T>
data class Error(val message: String, val retry: (() -> Unit)? = null) : UiState<Nothing>
}
// Usage in ViewModel
fun loadUsers(): Flow<UiState<List<UserProfile>>> = flow {
emit(UiState.Loading)
try {
val users = apiClient.fetchUsers()
emit(UiState.Success(users))
} catch (e: Exception) {
emit(UiState.Error(
message = e.localizedMessage ?: "Unknown error",
retry = { /* trigger reload */ }
))
}
}In Kotlin, when expressions over sealed types are exhaustive at compile time. Adding a new subtype forces handling it everywhere, which eliminates an entire category of runtime bugs. Interviewers specifically check that the candidate uses sealed interface (not sealed class) for this pattern, since interfaces allow more flexible hierarchies.
Kotlin/Wasm and Cross-Platform Compilation Targets
Kotlin/Wasm reached Beta status and brings near-native performance in browsers. While not yet a daily concern for Android developers, interviewers at companies with web+mobile products ask about it.
Key facts for the interview:
- Kotlin 2.3.20 delivered 4.6x faster string interpolation in Wasm through JS String builtins
- Binary sizes dropped approximately 5%
- Clean builds run 65% faster, incremental builds 21% faster
- The
@nativeInvokeannotation allows Kotlin objects to act as JavaScript functions
Kotlin/JS also gained the ability to implement Kotlin interfaces from TypeScript, removing a previous limitation. Combined with SWC support for transpilation, Kotlin now covers Android, iOS (via KMP), Web (via Wasm/JS), and server-side targets from a single codebase.
Scope Functions: A Deceptively Simple Interview Filter
Scope functions (let, run, with, apply, also) appear simple but differentiate experienced Kotlin developers. The interview question usually asks: "When do you use let versus apply?"
data class Request(
var url: String = "",
var method: String = "GET",
var headers: MutableMap<String, String> = mutableMapOf(),
var body: String? = null
)
fun buildRequest(): Request {
// apply: configure an object, returns the object
return Request().apply {
url = "https://api.example.com/users"
method = "POST"
headers["Content-Type"] = "application/json"
body = "{\"name\": \"Alice\"}"
}
}
fun processNullable(input: String?) {
// let: transform nullable, returns lambda result
val length = input?.let { value ->
println("Processing: $value")
value.trim().length
} ?: 0
// also: side effects, returns the original object
input?.also { println("Logging input: $it") }
// run: execute a block with receiver, returns lambda result
val result = input?.run {
// 'this' is the string
uppercase().take(10)
}
}The decision framework: apply for object configuration (returns receiver), let for null-safe transformations (returns lambda result), also for side effects (returns receiver), run for computing a result with receiver context.
Null Safety and the Danger of Double-Bang
Null safety remains a fundamental interview topic. The question "Why is !! dangerous?" tests whether a candidate truly understands Kotlin's type system.
fun findUser(id: String): User? {
// Returns null if user not found
return database.queryUser(id)
}
// Bad: !! defeats the purpose of null safety
fun riskyApproach(id: String) {
val user = findUser(id)!! // NullPointerException if null
println(user.username)
}
// Good: handle null explicitly
fun safeApproach(id: String) {
val user = findUser(id) ?: run {
println("User not found")
return
}
println(user.username)
}
// Good: provide default with Elvis operator
fun displayName(id: String): String {
return findUser(id)?.username ?: "Anonymous"
}A complete answer mentions that !! should only appear in test code or platform interop boundaries where null is genuinely impossible.
Start practicing!
Test your knowledge with our interview simulators and technical tests.
Conclusion
- Name-based destructuring in Kotlin 2.3.20 eliminates position-dependent bugs. Know all three compiler modes:
only-syntax,name-mismatch,complete - KMP is production-stable in 2026. Expect questions on expect/actual, shared module architecture, and Swift Export interop
- Context parameters replaced context receivers. The overload resolution change in 2.3.20 is a common trick question
- Coroutines and Flow dominate Android interviews. Master
StateFlowvsSharedFlow,WhileSubscribed, and structured concurrency - Sealed interfaces model UI state with compile-time exhaustiveness. Prefer
sealed interfaceoversealed class - Scope functions require a clear decision framework: receiver vs argument, return value vs receiver
- Null safety is non-negotiable. Articulate why
!!undermines the type system and demonstrate alternatives
Start practicing!
Test your knowledge with our interview simulators and technical tests.
Tags
Share
Related articles

Top 20 Jetpack Compose Interview Questions in 2026
The 20 most-asked Jetpack Compose interview questions: recomposition, state management, navigation, performance, and architecture patterns.

Mastering Kotlin Coroutines: Complete 2026 Guide
Learn to master Kotlin coroutines for Android development: suspend functions, scopes, dispatchers, and advanced patterns.

Jetpack Compose: Advanced Animations Step by Step
Complete guide to advanced Compose animations: transitions, AnimatedVisibility, Animatable, gestures and performance for smooth Android interfaces.