1. Introduction

In this tutorial, we’ll look at the actual keyword in Kotlin programming language.

2. Kotlin Multiplatform Essentials

First, we need to briefly discuss the Kotlin Multiplatform Module (KMM). This feature allows us to write code for multiple platforms in pure Kotlin. Without this knowledge, it’ll be impossible to understand what that keyword means.

To start with, the Kotlin Multiplatform Module is mainly used in mobile development. The goal is simple – we share the same business logic written in Kotlin between different iOS and Android code bases.

There will obviously be a lot of code that requires platform-specific APIs for things like UI rendering, working network or environment, etc. So, we will still have to write some fragments of code in Java/Kotlin for Android and Objective-C/Swift for iOS.

3. Shared Module

These platform-specific components will use our shared logic written in Kotlin. To make it a reality, KMM uses a Kotlin Native project. This project basically allows us to compile our Kotlin code into direct machine code, i.e., real binary for specific OS.

Still, our shared Kotlin module that is used in iOS and Android code bases can still contain some platform-specific APIs. For instance, let’s say we want to be able to get the current timestamp. No doubt, a lot of code might need this function, so it makes sense to share it. However, we need to access the system clock to get it via a native platform API.

This example is quite simple, but it demonstrates the purpose. We have the module that Kotlin and Swift modules share, and this shared module still contains some platform-dependent code.

4. Kotlin expect/actual Keywords

Thus, we have a shared module that has to access platform-specific API. And this shared module is, again, a pure Kotlin. So, having two systems, iOS and Android, we can achieve this by breaking the shared module into three parts.

First – we have separate common ios and android modules. In a common module, we write the shared logic. As we stated, if this common logic requires access to a platform-specific API, we use an expect keyword:

expect class DateTimeApi() {
    fun getCurrentTimestamp(): Long
}

This keyword basically declares a class with its functions and properties. There is no definition here since the actual definition will be platform-dependent. In other words, how we access the system clock differs in Android and iOS code. To define the actual definition of the expected functionality in the common module, we use an actual keyword:

actual class DateTimeApi actual constructor() {
    actual fun getCurrentTimestamp() : Long {
        return OffsetDateTime.now().toEpochSecond()
    }
}

Here, we have provided the actual definition for Android as an example. The Kotlin native compiler will ensure that each expected declaration has a corresponding definition in the final binary. Thus, the actual keyword represents the platform-specific definition of the certain functionality.

For completeness, the definition of the same function for iOS would look like this:

actual class DateTimeApi actual constructor() {
    actual fun getCurrentTimestamp(): Long {
        return NSDate.date().timeIntervalSince1970().toLong()
    }
}

In the code above, we use an Objective-C native API to get the current timestamp. This is the actual implementation for iOS.

5. Conclusion

In this article, we discussed two keywords from Kotlin – expect and actual.

The expect keyword provides a declaration of the API that will be implemented using platform-specific libraries. To provide definitions for these specific platforms, we use actual modifier. The compiler will ensure that all APIs with expect keyword in the signature have corresponding actual definitions in the binary.

The code used in this article can be found on GitHub.