Skip to content
This repository has been archived by the owner on Aug 10, 2021. It is now read-only.

Kotlin Generics to Swift Generics. #2429

Closed
horita-yuya opened this issue Nov 29, 2018 · 17 comments
Closed

Kotlin Generics to Swift Generics. #2429

horita-yuya opened this issue Nov 29, 2018 · 17 comments

Comments

@horita-yuya
Copy link

horita-yuya commented Nov 29, 2018

Is it possible to convert Kotlin generics to Swift Generics ?
At this time, it is converted to Any? (a.k.a Optional<Any>).

@olonho
Copy link
Contributor

olonho commented Nov 29, 2018

K/N does not interop with Swift directly yet, only via Objective-C, thus this feature request is not something we could help with at the moment.

@horita-yuya
Copy link
Author

yet and at the moment means it will be supported in the future?

@olonho
Copy link
Contributor

olonho commented Dec 3, 2018

It means I describe the current situation and cannot make any promises here.

@olonho olonho closed this as completed Dec 3, 2018
@sellmair
Copy link
Member

I would also love to have this functionality. This would open a lot of cool possibilities for our team.

@sellmair
Copy link
Member

sellmair commented Dec 24, 2018

@olonho
I am currently evaluating whether or not we could use this project to build Android and iOS applications for our customers. The fact that we are basically unable to use generics in shared APIs or generics when calling into platform APIs (eg. UIViewController.subViews becoming a List<*> instead of List<UIView>) is a huge problem for us. I am sure this is a really, really hard problem and most likely there are no plans for this yet, but we really, really need this to build a solid framework for our applications (without a lot of boilerplate and type wrapping)

@MarcinMoskala
Copy link

I must agree that generics visibility is an important part of interoperability. I believe that it is necessary if making common parts in Kotlin for Android and iOS is to become popular in mainstream programming.

@kpgalligan
Copy link
Contributor

Draft pull request generating generics in objc interop. Please comment if interested: #2850

@horita-yuya
Copy link
Author

amazing

@psinetron
Copy link

We need generics.

@Ribesg
Copy link

Ribesg commented Jun 20, 2019

Kotlin Generics can be converted to ObjC/Swift Generics as of Kotlin 1.3.40
See https://blog.jetbrains.com/kotlin/2019/06/kotlin-1-3-40-released/

@psinetron
Copy link

Yeah!

@desgraci
Copy link

desgraci commented Oct 2, 2019

Kotlin Generics can be converted to ObjC/Swift Generics as of Kotlin 1.3.40
See https://blog.jetbrains.com/kotlin/2019/06/kotlin-1-3-40-released/

I haven't been able to make this work yet :( Currently I have this:

kotlin {
targets{
        final def iOSTarget = System.getenv('SDK_NAME')?.startsWith("iphoneos") \
                              ? presets.iosArm64 : presets.iosX64

        fromPreset(iOSTarget, 'iOS') {
            binaries {
                framework('common') {
                    freeCompilerArgs.add("-Xobjc-generics")

But I still see Any? on my generic calls on the Xcode project, trying with iosX64 returns me the Cannot create binary debugFramework: binary with such a name already exists error, any tips, or any example on how to implement this correctly?

@SvyatoslavScherbina
Copy link
Collaborator

@desgraci this snippet is not enough to find the cause. Please post the entire Gradle script.

@desgraci
Copy link

desgraci commented Oct 4, 2019

@SvyatoslavScherbina sure no problem:

//this is what makes this module a cool kotlin/native
apply plugin: 'kotlin-multiplatform'
//this is for using sqldelight
apply plugin: 'com.squareup.sqldelight'
//this is for sync with xcode
apply plugin: 'co.touchlab.kotlinxcodesync'
//this to work with pods
//https://github.com/JetBrains/kotlin-native/blob/master/COCOAPODS.md
apply plugin: 'org.jetbrains.kotlin.native.cocoapods'
version = "1.0"

apply plugin: 'kotlinx-serialization'

//region WIP
//WIP please consider using a delegate!
apply plugin: 'com.android.library'

android {

    compileSdkVersion AndroidConfig.compileSdkVersion

    defaultConfig {
        minSdkVersion AndroidConfig.minSdkVersion
        targetSdkVersion AndroidConfig.targetSdkVersion
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

        //This is for MultiplatformSettings
        debug {
            // MPP libraries don't currently get this resolution automatically
            matchingFallbacks = ['release']
        }
    }

    packagingOptions {
        exclude 'META-INF/*.kotlin_module'
    }

}
//endregion

// workaround for https://youtrack.jetbrains.com/issue/KT-27170
configurations {
    compileClasspath
}

sqldelight {
    GymTrack {
        packageName = "com.vonderful.gymtrack"
        sourceFolders = ["sqldelight"]
        //not needed now, but meh
        schemaOutputDirectory = file("src/main/sqldelight/migrations")
    }
}


kotlin {
    targets {
        targetFromPreset(presets.android, 'android')

        final def iOSTarget = System.getenv('SDK_NAME')?.startsWith("iphoneos") \
                              ? presets.iosArm64 : presets.iosX64

        fromPreset(iOSTarget, 'iOS'){
            compilations.main{
                binaries {
                    framework("common") {
                        freeCompilerArgs.add("-Xobjc-generics")
                    }
                }
            }
        }

    }

    sourceSets {

        commonMain.dependencies {

            implementation kotlin('stdlib-common')

            //region Kotlin
            implementation "org.jetbrains.kotlin:kotlin-stdlib-common:${Versions.kotlin}"
            //endregion

            //region Coroutines
            implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:${Versions.kotlinCoroutines}"
            //endregion

            //region SQL Delight
            implementation "com.squareup.sqldelight:runtime:${Versions.sqlDelight}"
//            implementation "com.squareup.sqldelight:coroutines-extensions:${Versions.sqlDelight}"
            //endregion

            //region di
            implementation "org.kodein.di:kodein-di-erased:${Versions.kodein}"
            //endregion

            //https://github.com/Kotlin/kotlinx.serialization
            implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:0.13.0"

            implementation "io.ktor:ktor-client-core:${Versions.ktor}"
            implementation "io.ktor:ktor-client-json:${Versions.ktor}"
            implementation "io.ktor:ktor-client-serialization:${Versions.ktor}"
        }

        commonTest.dependencies {
            implementation 'org.jetbrains.kotlin:kotlin-test-common'
            implementation 'org.jetbrains.kotlin:kotlin-test-annotations-common'
        }

        //If you want to don't share the libs, don't use this and do your own imports on the dependencies...
        configure([androidMain]) {
            dependsOn commonMain
        }

        androidMain.dependencies {

            //region Coroutines
            implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.kotlinCoroutines}"
            //implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.kotlinCoroutines}"
            //endregion

            //region  SQL Delight
            implementation "com.squareup.sqldelight:android-driver:${Versions.sqlDelight}"
            //implementation "com.squareup.sqldelight:coroutines-extensions-jvm:${Versions.sqlDelight}"
            //endregion

            // The base will compile ok, but when ran, it will fail with an unresolveded reference
            // so we add this
            implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:${Versions.serializationRuntime}"
            //same we ktor, we are just sending those scary messages away!
            implementation "io.ktor:ktor-client-android:${Versions.ktor}"
            implementation "io.ktor:ktor-client-json-jvm:${Versions.ktor}"
            implementation "io.ktor:ktor-client-serialization-jvm:${Versions.ktor}"
        }

        androidTest.dependencies{
            implementation 'org.jetbrains.kotlin:kotlin-test'
            implementation 'org.jetbrains.kotlin:kotlin-test-junit'
            implementation "com.squareup.sqldelight:sqlite-driver:${Versions.sqlDelight}"
        }

        configure([iOSMain]) {
            dependsOn commonMain
        }

        iOSMain.dependencies {

            //region Coroutines
            implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-native:${Versions.kotlinCoroutines}"
            //endregion

            //region  SQL Delight
            implementation "com.squareup.sqldelight:ios-driver:${Versions.sqlDelight}"
            //endregion

            //same as in Android
            implementation "io.ktor:ktor-client-ios:${Versions.ktor}"
            implementation "io.ktor:ktor-client-json-native:${Versions.ktor}"
            implementation"org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:${Versions.serializationRuntime}"
            implementation "io.ktor:ktor-client-serialization-native:${Versions.ktor}"
        }

    }

//    //run the podscpec if you don't see the podspec :p !
    cocoapods {
        // Configure fields required by CocoaPods.
        summary = "Library for GymTrack app"
        homepage = "https://po.ta.to"
    }
}

xcode {
    projectPath = "../ios/Gym Track/Gym Track.xcodeproj"
    target = "Gym Track"
}

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

task copyFramework {
    def buildType = project.findProperty('kotlin.build.type') ?: 'DEBUG'
    def target = project.findProperty('kotlin.target') ?: 'iOS'
    //looking for commonDebugFramework
    dependsOn kotlin.targets."$target".binaries.getFramework("common", 'DEBUG').linkTask

    //arstDebugFramework
    doLast {
        def srcFile = kotlin.targets."$target".compilations.main.getBinary('FRAMEWORK', buildType)
        def targetDir = getProperty('configuration.build.dir')
        copy {
            from srcFile.parent
            into targetDir
            include 'app.framework/**'
            include 'app.framework.dSYM'
        }
    }
}

I've tried different combinations so far, but no luck, if there is anything else that I can bring to the table to help ouy let me know, btw this is my test generic class:

data class GenericTestData<T : Any>(val t: T)

but I still get the @interface SharecodeGenericTestData without the <T> at Swift

@SvyatoslavScherbina
Copy link
Collaborator

CocoaPods plugin creates its own framework internally.
Your snippet

framework("common") {
    freeCompilerArgs.add("-Xobjc-generics")
}

creates the second one. It should configure already created framework instead. Please refer to the documentation (see "Accessing binaries").

@desgraci
Copy link

desgraci commented Oct 4, 2019

Indeed, wasn't overwriting in the correct way the cocoapod's framework, worked like a charm, a good case of RTFabolousM, thank you for guiding me on this one @SvyatoslavScherbina

@TiferetCohenZemingo
Copy link

Hi, maybe you can help me. I followed this tutorial: https://medium.com/@fandygotama/kotlin-multiplatform-reactive-a45263e1fd7a and got tuck right in the beginning. The sync fails:

Build file '/myPath/kmmmovies/core/build.gradle' line: 16

A problem occurred evaluating project ':core'.
> Operation is not supported for read-only collection

line 16 is the freeCompilerArgs.add("-Xobjc-generics"):
fromPreset(iOSTarget, 'iOS') { binaries { framework("core") { freeCompilerArgs.add("-Xobjc-generics") } }
Can anyone tells me what am I doing wrong?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants