I know that swift doesn't have covariance for generics, so I wouldn't expect the following to work, but it does and prints true:
let foo: SharedNetworkStateUIModel<Parent> = MRE.test()
print(foo is SharedNetworkStateUIModel<Child>)
Where Objective-C code is this: (simplified for the forums)
@interface Parent : NSObject
@end
@interface Child : Parent
@end
@interface SharedNetworkStateUIModel<__covariant UIModel> : NSObject
@end
@interface SharedNetworkStateUIModelNone : SharedNetworkStateUIModel<Child *>
@end
@implementation MRE
+ (SharedNetworkStateUIModel<Parent *> *)test {
return [[SharedNetworkStateUIModelNone alloc] init];
}
However checking for the SharedNetworkStateUIModelNone
type directly does not work, unless you first cast it to SharedNetworkStateUIModel<Child>
or Any
.
let foo: SharedNetworkStateUIModel<Parent> = MRE.test()
let bar: SharedNetworkStateUIModel<Child> = foo as! SharedNetworkStateUIModel<Child>
print(foo is SharedNetworkStateUIModel<Child>)
print(bar is SharedNetworkStateUIModelNone)
print(foo is SharedNetworkStateUIModelNone)
print((foo as Any) is SharedNetworkStateUIModelNone)
will output:
true
true
false
true
There is even a warning on the 3rd print statement:
Cast from 'SharedNetworkStateUIModel' to unrelated type 'SharedNetworkStateUIModelNone' always fails
even though SharedNetworkStateUIModelNone
is a subtype of SharedNetworkStateUIModel<Child>
which is a subtype SharedNetworkStateUIModel<Parent>
.
This gives a further problem in that, the compiler thinks it's always false when it shouldn't be, and so when optimizations are turned on in Release configuration it replaces the check with false. it can be forced to the check as expected with as Any
but I'm not sure that guarantees it won't be optimized out in the future.
So it seems like the type checking and casting is partially broken when it comes to Objective-C generics with covariance?