Why this code generates the following warning?
@interface Foo : NSObject
- (void)m:(id _Nullable)p;
@end
@interface Bar : Foo
- (void)m:(id _Nonnull)p;
@end
conflicting nullability specifier on parameter types, '_Nonnull' conflicts with existing specifier '_Nullable' [-Wnullability]
But the other way does not generate warnings:
@interface Foo : NSObject
- (void)m:(id _Nonnull)p;
@end
@interface Bar : Foo
- (void)m:(id _Nullable)p;
@end
Is it because in the second case we going from more restrictive to less restrictive?
It's all because of Liskov substitution principle
According to this principle:
if S is a subtype of T, then objects of type T may be replaced with objects of type S without altering any of the desirable properties of the program.
In your example: Bar
is subtype of Foo
. So you should be able to replace instance of Foo
with instance of Bar
.
In other words, imagine method
- (void)doSomethingWith:(Foo *)object {
[object m:nil];
}
If you pass to this method instance of Foo
- everything is ok. But you may not pass to it instance of Bar
- because you may not call [Bar m:nil]
Here you can see, that this code breaks Liskov substitution principle.
Otherwise, in the second example, everything is fine.
Imagine method:
- (void)doSomethingWith:(Foo *)object {
[object m:@""]; // _Nonnull requirement
}
As you can see, you can pass to this method instances of both Foo
and Bar
classes.
NOTE: Here it is important to note that in Objc (unlike Swift) these rules are not so strict and you can easily deceive the compiler.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With