Right now, there is no way to get a KClass instance from Swift / ObjC.
Let's say a Kotlin function is declared as such:
fun <T : Any> getInstance(type: KClass<T>)
The function getInstance is accessible but not callable from Swift.
This is because there is no way in ObjC / Swift to access a KClass instance.
Kotlin/Native should provide a way to access KClass instances directly from Swift / ObjC:
let manager = SampleKt.getInstance(type: Manager.kotlinClass) as! Manager
The current workaround is to explicitly make the KClass object accessible, such as:
object KotlinClasses {
fun manager() = Manager::KClass
}
So we can use it in Swift:
let manager = SampleKt.getInstance(type: KotlinClasses().manager()) as! Manager
This is not a scalable solution since the framework developper has to anticipate every classes the app developper will need.
let manager = SampleKt.getInstance(type: Manager.kotlinClass) as! Manager
Not sure if this is implementable for protocols.
Do I understand correctly that getInstance can be used for protocols too?
Yes, it must exist for Kotlin interfaces, which are translated to protocols.
I understand that Manager.kotlinClass is not possible as-is if Manager is a Kotlin interface (translated to protocol).
I think there are many ways to circumvent this:
KotlinClasses of my example workaround) => SampleKt.getInstance(type: KotlinClasses.Manager()).Meta object that would allow to acces the KClass => SampleKt.getInstance(type: Manager.Meta().kotlinClass()).func kotlinClass(meta: Any.Type) -> KotlinKClass that would of course only work for Kotlin-translated classes => SampleKt.getInstance(type: kotlinClass(Manager.self)).@SalomonBrys the first one, in my opinion, scales poorly, names clashing may be a thing, but the other 2 options looks like nice additions to me, the 2nd is nice because is extensible, any extra metadata can be appended there, maybe some more "reflection"-kind of methods also can be included later, the last one looks clean and easier to implement to me, but it's not as extensible.
I have mixed feelings about solutions to this issue, giving limitations and such, but I truly think this issue is relevant.
I consider a bit different approach currently:
to provide getKClass(ObjCClass): KClass<*>? and getKClass(ObjCProtocol): KClass<*>? within Kotlin/Native standard libraries.
This would enable
kotlinClass-like function to your framework explicitly if required.I mean something like this: https://github.com/JetBrains/kotlin-native/pull/3036/files#diff-c138c1120f091ad4bbf41fc9adb26ab5R11
(See this Kotlin and Swift code as an example).
@SalomonBrys what do you think?
That looks perfect.
Some questions:
getKClass is working for standard types, such as String or Int.qualifiedName is supported. Not very important but useful (and supported by "native" Kotlin KClass).Other than that, this fits my needs perfectly :)
Your test do not show if getKClass is working for standard types, such as String or Int.
This is not supported by the API. What do you need this for?
Your test do not show if qualifiedName is supported. Not very important but useful (and supported by "native" Kotlin KClass).
The resulting KClass is equivalent to what ::class produces, so .qualifiedName is supported.
In the Kodein-DI container, it is possible to bind constants:
val kodein = Kodein {
constant("name") with "Salomon"
constant("answer") with 42
}
Such constants are then retrievable like this:
val name: String by kodein.instance("name")
val answer: Int by kodein.instance("answer")
In Swift, they would be retrieved like this:
let name: String = kodein.Instance(getKClass(String.self), "name") as! String
let answer: Int = kodein.Instance(getKClass(Int.self), "answer") as! Int
However, I can think of many ways to circumvent the absence of primitive KClass in the API, so this is definitely not blocking ;)
Thank you for the explanation.
Providing support for classes like String and primitive types here is somewhat complicated, especially considering Objective-C involved between Kotlin and Swift.
For example, String.self or Int.self aren't instances of AnyClass corresponding to Objective-C Class and Kotlin ObjCClass types.
No problems: this can be easily provided at the library level :)
Fixed with #3036 then. Will likely be available with 1.3.50.
Could someone provide an example on how can I use this in Swift in MPP? I can't resolve the getOriginalKotlinClass call
@kar could you provide more details?
Are you trying to call getOriginalKotlinClass from Kotlin or Swift code? If it is Kotlin, please make sure that you have import kotlinx.cinterop.getOriginalKotlinClass and that this file belongs to target-specific source set, not common one.
@SvyatoslavScherbina from Swift. Basically my question is what should we expect when it comes to Kotlin classes in Swift, how should (and shouldnt) we use them. I couldn't find any details in the docs.
from Swift.
Then please add the method calling getOriginalKotlinClass to your Kotlin code, and then call this method from Swift, see e.g. https://github.com/JetBrains/kotlin-native/issues/2988#issuecomment-497268161.
Basically my question is what should we expect when it comes to Kotlin classes in Swift, how should (and shouldnt) we use them.
Your question is not clear to me.
I couldn't find any details in the docs.
Do you mean these docs?
https://kotlinlang.org/api/latest/jvm/stdlib/kotlinx.cinterop/get-original-kotlin-class.html
Yeah. It wasn't clear to me on how to use it, but I'm a K/N beginner. Your explanation, works, thanks a ton!
Most helpful comment
I consider a bit different approach currently:
to provide
getKClass(ObjCClass): KClass<*>?andgetKClass(ObjCProtocol): KClass<*>?within Kotlin/Native standard libraries.This would enable
kotlinClass-like function to your framework explicitly if required.