Multiplaform: Using platform dependant import from common

#1

we have sucessfully used multiplatform to create a multi-platform library, with versions for each platform.
This gives a libJVM and a libNative, each of which contain the same classes and funtions. e.g., both contain an equivalent lib.someFunction implementation

for a multiplatform project, this provides a dependency for each platform so

import lib.someFunction // not actual name, just simplified

will work for each platform.

But how do we make someFunction available to common? Even though the import is the same for each platform, so the syntax of the import should work, commonMain/commonTest cannot seem to have imports that are supplied by platform dependencies. Or can they, and if so, how?

#2

You will have to use the expect and actual machinery to define the common functions that only have implementations in individual platforms. Have a look here.

#3

As I said, we have successfully built a multiplatform library, which of course uses expect / actual as described.

However, the answer by @pdvieze describes how build multiplatform code (which is easy and works well) but it is not a useful answer for how to use a multiplatform library within another multiplatform project.

The only obvious way to use expect actual as defined there is to import the same function for each platform, and wrap that function in a new function. Repeat the exact same code for each platform. Then have all possible imports and create wrappers for them and repeat that boilerplate in each platform.

So in place of

import lib.someFunction

in common, we can have

expect multiSomeFunction()  // need full signature here, although import does not

Then for every platform we repeat the exact same code

import lib.someFunction
actual multlSomeFunction () = someFunction()

And repeat this boilerplate code over and over for every export from the library, and then copy and paste the exact same boilerplate into every platform ??

The end result of that is multiplatform would be a joke as soon as common code needs make use of multiplatform libraries.

You are better off creating separate projects for each platform, because you will have less repeated boilerplate code than with multiplatform.

The guys designing multiplatform are better than that, which suggests using expect/actual to wrapper for functions implemented in multiplatform libraries is not the solution. Hopefully there is a solution.

We have cases where common seems to be able to import from platform based dependencies, which would be (and in those cases is) a perfect solution. However it seems it does not always work, and always syntax highlights as an error, even when it does work.

#4

It seems the answer may lie in here…
https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#experimental-metadata-publishing-mode

Still some lack of explanation but the general idea is that for example, commonMain sourceSet could have a variable dependancy that varies with platform being built.

The answer lies in correct dependency configuration, and does not utilise expect/actual.

It would perhaps make most sense if common only pulled names from common component of whatever platform is included in its own dependencies, but actually code linked came from a platform specified in the relevant platform dependency. This seems to be trying to achieve that result by a more convoluted approach using tags… but having found this link we will try and see what comes from it.

#5

Ok, I see where you are going. Unfortunately while it is possible to resolve an expected through an actual typealias, there is no direct equivalent for functions. The “best” way to do so is to have the platform actual just be an inline function that forwards to the function you need. It is not technically an alias but functions more or less like it.

Btw. If you use multiplatform libraries written in Kotlin, this should just work out of the box (but you need to make the metadata/common package available). You do need to depend on the common version of the library in the common source set. Btw. do check (e.g. your maven local) that all needed artifacts are published (including the common archive - which doesn’t actually contain class files).

#6

Back to the original question, and it has become clear typealias and expect/actual are unrelated to the actual solution to that problem. The actual solution is just to get the imports and dependenices working correctly.

However your point about the common archive not containing class files does seem to be the correct solution. What is required is a dependency for commonMain & commonTest which as you say contains no class files. Then the individual platform specific dependency in platformMain and platformTest.

Strangely, and perhaps misleadingly, we have one example that builds correctly where commonTest has no dependency specified buy sucessfully imports and uses code from the library, even though the only dependency is for platformTest, and is the platform specific version.

There is logic for the metadata to ensure the correct version is selected from the repository, but it seems that specifically selecting the common archive for common, and the relevant platform module in the platform, would not really need reliance on the metadata and be a more reliable approach to cover all possible cases.

#7

You do need to depend on the common version of the library in the common source set. Btw. do check (e.g. your maven local) that all needed artifacts are published (including the common archive - which doesn’t actually contain class files)

When using the original multiplatform logic, we did have a common artifact, but now the library generated using the multiplatform plugin does not generate this artifact. We have been using the base
name of the lib as a dependency for common, and it seems to select the correct dependency in most cases, but it would be far better to have an explicit common dependency without class files that only defines that which is in common … as you seem to describe.

If you know of an example repo of how to create such an archive using the new multiplatform it would be greatly appreciated.