Purpose of Expect/Actual

So, I’m in the early stages of exploring Multiplatform with a small(as of now) personal project. I wrote an expect/actual function to retrieve user input and it seemed neat. Then I wrote another function and refactored a few things and the expect/actuals broke. I still don’t quite know why, but in digging around looking for more information about expect/actual I realized that maybe interfaces would be a better way to go.

So the question is: since we already have interfaces, what is the actual (or expected :stuck_out_tongue:) benefit of using expect/actual, or what is a situation where it is better or even necessary when compared to using an interface?

1 Like

Let’s say you’re writing a graphics-based native application. You intend to release binaries on Windows, Mac, and Linux, but you want a majority of your code to be common across all three platforms. However, for certain functions you need to access platform-specific APIs – DirectX on Windows, Metal on Mac, and Vulkan(?) on Linux. So now in your common code you need one function that does the same thing but 3 different ways on all the platforms. Let’s say this function is supposed to draw a circle with a border color and a fill color. In the common code, you can define an expect fun which expects a platform-specific implementation for this circle drawing function. Then, in your Windows/Mac/Linux code you write the code for drawing your circle using the platform-specific graphics apis as actual funs which have the same signature as the expect fun in the common code.

That’s what expect/actual is for. It’s a way to define in common code that you “expect” to be able to call the same function across multiple platforms. When you implement the “actual” fun, it interacts with platform specific libraries. Regardless, the common code can still call into the platform code across all platforms.

Does that make sense?

1 Like

You could get away without having expect and actual. As you point out, simply implementing an interface on each platform and, through service lookup or dependency injection, provide the correct implementation then your code would be fully platform independent without ever using expect/actual.

Imagine a project with many multiplatform APIs. Some of the APIs you wish to use are classes, others are top level functions or properties. You could embark on the large effort of creating interfaces to bind all of these things and use dependency injection or service lookup.

Expect/actual provides this without much cost (just defining the API). Kind of like a built in form of dependency injection. It allows you to create classes/functions/properties instead of just interfaces without wrapping them in some provider interface for access.

2 Likes

The team actually answered this during a Kotlin 1.4 online event Q&A: Kotlin 1.4 Online Event, Day 3: Kotlin everywhere: Android, Mobile Multiplatform, Kotlin/JS - YouTube

3 Likes