Jason Zhao
04/09/2023, 7:10 AMexpect
-actual
feature, rather than with interfaces. The issue is that unlike a typical Multiplatform application where, say, the server part targets only JVM while the client only targets JS, in my case my two applications can target the same physical platform. One is JVM only, while the other is multiplatform, including JVM.
For example in the Multiplatform gradle config, I would need a "jvm1" source set and a "jvm2" source set which actually compile to the same platform but need to have different dependencies and compile to different binaries, hence they really need to be treated by Kotlin Multiplatform as different platforms. I am wondering whether doing something like this is possible.
Edit: It seems that according to this StackOverflow post, combining two JVM targets like JAR + Android would cause Kotlin to not recognize the platform as JVM anymore, but in my case that is fine since one of my backends is multiplatform so my common module needs to be multiplatform code anyway. Therefore, the example I gave in the last paragraph may be bad, but overall I am still wondering whether having 2 targets compiling to the exact same platform is possible.Adam S
04/09/2023, 8:56 AMCLOVIS
04/09/2023, 9:52 AMHowever, for this project, performance is quite important, so I want there to be no code wrapping/abstractions in the compiled code.Don't assume, measure. The JVM notices that an interface has only one implementation, and inlines everything. It's unlikely that this has any impact whatsoever on anything. What I usually do when facing this situation is to go with multiple Gradle projects:
shared/
src/commonMain/…
build.gradle.kts
impl1/
src/commonMain/…
build.gradle.kts
impl2/
src/commonMain/…
build.gradle.kts
settings.gradle.kts
The shared
project declares an interface that both implementation projects implement, then they declare their own expect-actual mechanism.
This way, each implementation is free to have its own dependencies, and is published completely independently.Jason Zhao
04/09/2023, 5:59 PMyou can have several targets for the same platform, but you’ll need some Gradle configuration on both the producer and consumer so that they can be differentiatedAwesome, that documentation actually appears to cover my exact use case. I don't know how I didn't find it earlier. Although I still need to find out how to get projects using my API to "inherit" these custom platforms/targets from the API, and therefore have platform-specific code themselves.
Don't assume, measure. The JVM notices that an interface has only one implementation, and inlines everything. It's unlikely that this has any impact whatsoever on anything.One issue is that I am still concerned about is performance on non-JVM platforms. However, there are also other benefits to laying out my project in Kotlin Multiplatform platforms compared to the usual method of just using Gradle. For example let's say I implement this API through Kotlin Multiplatform, and that I have a data structure class in the common API that is just a wrapper in platform #1, but has a full implementation from scratch in platform #2. Then anything using the API and targeting platform #2 can directly use the internal implementation methods of that data structure. If I used multiple modules and interfaces instead, I would need to cast that interface into the specific implementation class every time. Maybe the JVM can optimize that out too, but at the very least it is more verbose when coding. Another example is with platform-dependent static APIs, where I can just use an
expect object
in Kotlin Multiplatform but I would need an interface with a singleton instance using traditional Gradle.
Plus, I would have to split each module that depends on the main API into 3 different modules as well (1 for common and 1 for each platform) which is harder to maintain.