Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective-C overriding _Nullable parameter with _Nonnull parameter

Tags:

objective-c

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?

like image 781
Antonio Avatar asked May 14 '18 19:05

Antonio


Video Answer


1 Answers

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.

like image 84
Anton Belousov Avatar answered Oct 23 '22 05:10

Anton Belousov