kotlinadvanced

Kotlin Multiplatform — Expect/Actual Declarations

Share code across platforms with expect/actual: common interfaces, platform-specific implementations.

kotlin
// ============================================
// commonMain/src/Platform.kt
// ============================================

// Expect declarations — common interface
expect fun platformName(): String
expect fun currentTimeMillis(): Long
expect class UUID {
    companion object {
        fun randomUUID(): UUID
    }
    override fun toString(): String
}

// Common code using expect declarations
class AppInfo {
    val platform = platformName()
    val startTime = currentTimeMillis()
    val instanceId = UUID.randomUUID().toString()

    fun info() = "App on $platform (id: $instanceId)"
}

// Common business logic
interface Repository<T> {
    suspend fun findAll(): List<T>
    suspend fun findById(id: String): T?
    suspend fun save(item: T)
    suspend fun delete(id: String)
}

data class Note(
    val id: String = UUID.randomUUID().toString(),
    val title: String,
    val content: String,
    val timestamp: Long = currentTimeMillis()
)

expect class NotesRepository() : Repository<Note>

// Shared ViewModel
class NotesViewModel(private val repo: NotesRepository = NotesRepository()) {
    suspend fun getAllNotes(): List<Note> = repo.findAll()
    suspend fun addNote(title: String, content: String) {
        repo.save(Note(title = title, content = content))
    }
    suspend fun removeNote(id: String) = repo.delete(id)
}

// ============================================
// jvmMain/src/PlatformJvm.kt  
// ============================================

/*
actual fun platformName(): String = "JVM ${System.getProperty("java.version")}"
actual fun currentTimeMillis(): Long = System.currentTimeMillis()

actual class UUID private constructor(private val impl: java.util.UUID) {
    actual companion object {
        actual fun randomUUID(): UUID = UUID(java.util.UUID.randomUUID())
    }
    actual override fun toString() = impl.toString()
}

actual class NotesRepository actual constructor() : Repository<Note> {
    private val notes = mutableListOf<Note>()
    override suspend fun findAll() = notes.toList()
    override suspend fun findById(id: String) = notes.find { it.id == id }
    override suspend fun save(item: Note) { notes.add(item) }
    override suspend fun delete(id: String) { notes.removeIf { it.id == id } }
}
*/

// ============================================
// jsMain/src/PlatformJs.kt
// ============================================

/*
import kotlin.js.Date

actual fun platformName(): String = "JS/Browser"
actual fun currentTimeMillis(): Long = Date.now().toLong()

actual class UUID private constructor(private val value: String) {
    actual companion object {
        actual fun randomUUID(): UUID {
            val chars = "0123456789abcdef"
            val uuid = buildString {
                repeat(32) { append(chars.random()) }
            }
            return UUID(uuid)
        }
    }
    actual override fun toString() = value
}

actual class NotesRepository actual constructor() : Repository<Note> {
    private val notes = mutableListOf<Note>()
    override suspend fun findAll() = notes.toList()
    override suspend fun findById(id: String) = notes.find { it.id == id }
    override suspend fun save(item: Note) { notes.add(item) }
    override suspend fun delete(id: String) { notes.removeIf { it.id == id } }
}
*/

Use Cases

  • Sharing business logic across JVM and JS
  • Platform-specific API abstraction
  • Multiplatform library development

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.