Hi everyone! I have a question about interop of ge...
# multiplatform
n
Hi everyone! I have a question about interop of generics in ObjC/Swift. If I have a class with a generic in kotlin, let's say
GenericBox<T>
:
Copy code
class GenericBox<T : Any>(val value: T)
And I want to use
List<String>
as a generic type of this `GenericBox`:
Copy code
fun getListOfStringsBox(): GenericBox<List<String>> {
    return GenericBox(listOf("List", "of", "strings"))
}
I noticed that in Objective C the interface is generated correctly and all the generics are there:
GenericBox
has
T
and the signature of
getListOfStringsBox()
has
SharedGenericBox<NSArray<NSString *> *> *
as a return type
Copy code
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("GenericBox")))
@interface SharedGenericBox<T> : SharedBase
- (instancetype)initWithValue:(T)value __attribute__((swift_name("init(value:)"))) __attribute__((objc_designated_initializer));
@property (readonly) T value __attribute__((swift_name("value")));
@end

__attribute__((swift_name("Demo")))
@interface SharedDemo : SharedBase
+ (instancetype)alloc __attribute__((unavailable));
+ (instancetype)allocWithZone:(struct _NSZone *)zone __attribute__((unavailable));
+ (instancetype)demo __attribute__((swift_name("init()")));
@property (class, readonly, getter=shared) SharedDemo *shared __attribute__((swift_name("shared")));
- (SharedGenericBox<NSArray<NSString *> *> *)getListOfStringsBox __attribute__((swift_name("getListOfStringsBox()")));
@end
But when I try to access the
value
from
GenericBox
, the type is lost and it returns
NSArray<Any>
instead of
NSArray<NSString>
. This happens only to
List -> NSArray
interop and doesn't happen if there are two kotlin types with generics nested one to another, eg.
GenericBox<ChildGenericBox<String>>
(in this case both types will be preserved). Is it a limitation of Objective C
NSArray
type (or lightweight generics supported there) or it's a KMP compiler bug? I couldn't find an issue reported to JB issue tracker (or maybe I searched it badly).
I prepared a simple demo project to show this issue in case somebody wants to play around: https://github.com/anthony-novikov/objc-list-kmm-binding-demo
j
See the docs:
Generics can only be defined on classes, not on interfaces (protocols in Objective-C and Swift) or functions.
Because
List
is an interface, the generic type is lost in the Objective-C interop.
n
I don't think this is entirely the reason. I would have understood this if kotlin
List
was exported to ObjC as
@protocol KotlinList
as it happens to
Iterator<T>
for example. KMP exports
List<T>
to Objective C as
NSArray<T>
and even in my sample app this construction will keep the generic type of a list item
Copy code
class GenericListBox<T : Any>(val value: List<T>)
So I believe there is something else that doesn't allow to use
List
as a generic type.
j
Nested generics are also not supported. The generic type of a generic type will be lost.
n
no it won't.
Copy code
GenericBox<ChildGenericBox<String>>
works as well