Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access Kotlin Standard Library from Swift

In my Kotlin Multiplatform project, I'm trying to access Kotlin types defined in kotlin-stdlib from Swift.

TL;DR: StdLib types/methods seem not to result in header definitions, I'd like a solution that doesn't involve writing lots of boilerplate code

My scenario

I have an interface defined in Kotlin ...

interface MyKotlinInterface {
  fun run() : Sequence<String>
}

... and implemented this interface in Swift ...

class MySwiftClass : MyKotlinInterface {
  func run() -> KotlinSequence {
    // return sequenceOf("foo")
  }
}

... there I'm trying to create a Sequence but there are no methods from the kotlin.sequences package available (e.g. generateSequence).

Is it actually possible to access Kotlin framework types or methods beyond what I define in my code -- if yes, how? Furthermore, how can this be achieved without writing boilerplate code?

Further details

Having a look into the generated Objective-C header file, I see definitions for my class (obviously) and basic Kotlin types. What's missing is basically everything from the standard library functionality (I care for everything Sequence-related).

My build.gradle.kts looks like:

plugins {
  kotlin("multiplatform") version "1.3.0"
}

kotlin {
    targets { /* ... */ }

    sourceSets {

        getByName("commonMain") {
            dependencies {
                api("org.jetbrains.kotlin:kotlin-stdlib-common")
            }
        }

        // ...

        getByName("iosMain") {
            dependencies {
                api("org.jetbrains.kotlin:kotlin-stdlib")
            }
        }
    }
}

Having the kotlin-stdlib defined as a dependency for the iOS target, I would expect those to become actually available from Swift.

Minimal working example

https://github.com/panzerfahrer/so-mwe-kotlin-mpp-swift

Current solution approach

The only solution I came up with, is writing the desired function for the iOS target:

fun <T : kotlin.Any> generateSequence(nextFunction: () -> T?): kotlin.sequences.Sequence<T> = kotlin.sequences.generateSequence(nextFunction)

This works ok-ish but is highly unsatisfying as it requires lots of boilerplate code. Additionally, extension functions cannot be made available this way and would require more boilerplate code or even rewriting parts of the standard library.

Desired solution

I like to avoid writing boilerplate code as much as possible. What I actually only care about, is to have (in my case) Sequence fully accessible from Swift. My feeling is, it would be sufficient to make the compiler generate selected or all header definitions for the standard library functionality.

like image 901
Brian Avatar asked Nov 08 '22 00:11

Brian


1 Answers

Do you really need lazy computation (aka Sequence) in your Kotlin code? If no, I would recommend using List<T> instead (and it maps to Swift directly).

For Sequence implementation, a workaround could be to export a factory function from your Kotlin library, e.g. you may declare a function like

fun <T : kotlin.Any> generateSequence(nextFunction: () -> T?)
    = kotlin.sequences.generateSequence(nextFunction)

You may select any other factory function for Sequence, that matches your use-case.

In general, there are too many functions in the Kotlin standard library. Exporting them all to Swift will create too many useless symbols in the binary and increase the compilation time.

like image 101
Eugene Petrenko Avatar answered Nov 11 '22 08:11

Eugene Petrenko