Mastering expect and actual in Kotlin Multiplatform
Kotlin Multiplatform (KMP) is a powerful way to share code across different platforms like Android, iOS, Desktop, and Web. However, some features are platform-specific (like accessing the file system, Bluetooth, or logging). This is where expect and actual come into play!
Get Bharath Dhakar’s stories in your inbox
Join Medium for free to get updates from this writer.
In this article, we’ll break it down using the Feynman Technique, making it so simple that you could explain it to a 5-year-old.
🔹 Step 1: Feynman Technique — Beginner-Friendly Explanation
Universal Remote Analogy 🎮
Imagine you are building a universal remote that works with both a TV and an Air Conditioner (AC).
- You want a single button to turn ON both devices.
- However, the way the TV turns ON is different from how the AC turns ON.
In Kotlin Multiplatform, we solve this using expect and actual:
- The
expectkeyword defines a common interface (like the "ON" button of the remote). - The
actualkeyword provides platform-specific implementations (how the TV and AC interpret "ON").
Code Example:
✅ Common Code (Shared Across Platforms)
// Common code (shared across all platforms)
expect class UniversalRemote {
fun turnOn()
}✅ Platform-Specific Implementations:
// Implementation for TV (Android)
actual class UniversalRemote {
actual fun turnOn() {
println("Turning on the TV...")
}
}// Implementation for AC (iOS)
actual class UniversalRemote {
actual fun turnOn() {
println("Turning on the AC...")
}
}🎯 Now, when you call UniversalRemote().turnOn(), the correct implementation is automatically chosen depending on the platform!
🔹 Step 2: Deepening Understanding — How It Works in Kotlin Multiplatform
🔥 Why Do We Need expect/actual?
Kotlin Multiplatform allows code sharing, but some features are platform-dependent. Instead of writing separate codebases, we define expected declarations (expect) in common code, and each platform provides its actual implementation (actual).
🔷 What Can Be expect/actual?
- Classes
- Functions
- Properties
- Enums
Example: Platform-Specific File System Access
Let’s say we need to get the file path on Android and iOS. Since each OS stores files differently, we use expect/actual:
✅ Common Code (Shared)
expect fun getFilePath(): String✅ Platform-Specific Implementations:
// Android-specific implementation
actual fun getFilePath(): String {
return "/storage/emulated/0/Download"
}// iOS-specific implementation
actual fun getFilePath(): String {
return "/Users/username/Documents"
}🎯 Now, calling getFilePath() will return the correct file path depending on the platform! 🚀
🔹 Step 3: Socratic Questioning — Let’s Think Deeper!
🤔 Ask yourself:
- Why do we need
expect/actualinstead of just using interfaces? - What happens if you define an
expectfunction but forget to provide anactualimplementation? - Can
expect/actualbe used for third-party libraries? Why or why not? - Would
expect/actualbe useful in a cross-platform game engine? How?
Take a moment to think. What are your answers? 🤔
🔹 Step 4: Active Recall — Your Turn to Summarize!
Without looking back, try to recall and explain:
- What is
expect/actualin Kotlin Multiplatform? - How does it help in cross-platform development?
- Can you give an example where
expect/actualwould be useful?
Try it out! Then check back to see if you missed anything. ✅
🔹 Step 5: Common Mistakes & Misconceptions
❌ Mistake 1: Defining expect but forgetting actual
- If you define
expect fun myFunction(), but don't provide anactualversion on all platforms, you'll get a compilation error.
❌ Mistake 2: Expecting expect functions to work in common code
- The
expectfunction is just a declaration. It does nothing until anactualimplementation is provided.
❌ Mistake 3: Trying to provide an actual implementation in shared (common) code
actualcan only exist in platform-specific code (Android/iOS/etc.).
🔹 Step 6: Practical Application — Let’s Write Some Code!
💡 Challenge: Implement a Logger class using expect/actual that:
- Uses
Log.d()in Android - Uses
println()in iOS
✅ Common Code (Shared)
expect class Logger() {
fun log(message: String)
}✅ Platform-Specific Implementations:
// Android Implementation
actual class Logger {
actual fun log(message: String) {
Log.d("MyApp", message)
}
}// iOS Implementation
actual class Logger {
actual fun log(message: String) {
println("iOS Log: $message")
}
}🎯 Try running this in a Kotlin Multiplatform project! 🚀
🔹 Step 7: Teach Back Method — Explain It to Me!
Now, I want you to teach expect/actual back to me. Imagine I’m a beginner. Explain:
- What
expect/actualis in simple terms - How it works in Kotlin Multiplatform
- A real-world use case





