-
Notifications
You must be signed in to change notification settings - Fork 6k
Annotate nullability on FlutterEngine to make swift writing more ergonomic #11808
Conversation
dnfield
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would NS_ASSUME_NONNULL or whatever be helpful here?
| * @param projectOrNil The `FlutterDartProject` to run. | ||
| */ | ||
| - (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)projectOrNil; | ||
| - (nonnull instancetype)initWithName:(nonnull NSString*)labelPrefix project:(nullable FlutterDartProject*)projectOrNil; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can return null
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you mean the return type? Can it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It shouldn't, but the impl has if (self) in there. Maybe someone more familiar with ObjC and Swift could help on this - my inclination is that becuase the impl explicitly assumes that [super init] can return null, we should treat it as such, but I found something in the docs suggesting that NSObject init is never expected to return null. @jmagman might know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-[NSObject init] is actually not decorated with nonnull but should be assumed to be nonnull. So unless this initializer actually returns null in some cases (common enough, see -[NSCoding initWithCoder:]) or it's baseclass designated initializer can return null, you can assume nonnull.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's a convention but since we know this is NSObject, I don't think it can return nil
https://opensource.apple.com/source/objc4/objc4-532/runtime/NSObject.mm (it just returns self). Other supers can return nil but we also NSAssert non-nil (I don't think we have DNS_BLOCK_ASSERTIONS turned on anywhere)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case, should we just change the impl to assert not nil, and remove the if self as part of this patch?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it already asserts non nil and doesn't if self (if I understood you correctly)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh right. Ok, I was misremembering.
| */ | ||
| - (instancetype)initWithName:(NSString*)labelPrefix | ||
| project:(FlutterDartProject*)projectOrNil | ||
| - (nonnull instancetype)initWithName:(nonnull NSString*)labelPrefix |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can return null
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here. I'm not sure how would it
| * setting the locale. | ||
| */ | ||
| @property(nonatomic, readonly) FlutterMethodChannel* localizationChannel; | ||
| @property(nonatomic, readonly, nonnull) FlutterMethodChannel* localizationChannel; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be null
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this would be only after destroyContext right? Will change and update doc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now yes.
| * @see [Navigator Widget](https://docs.flutter.io/flutter/widgets/Navigator-class.html) | ||
| */ | ||
| @property(nonatomic, readonly) FlutterMethodChannel* navigationChannel; | ||
| @property(nonatomic, readonly, nonnull) FlutterMethodChannel* navigationChannel; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the channels can be null
f1a96cf to
58a5f8d
Compare
|
I don't have a strong preference. I think everything being explicit is nice but I either's fine for me. |
jmagman
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The right way to do this is to wrap all headers is NS_ASSUME_NONNULL and only annotate nullable and _Nullable (block params) and null_resettable (setter can take nil, getter will always return nonnull).
Crack open NSString.h and copy any patterns you see in there. Foundation patterns are the gold standard.
| * @param projectOrNil The `FlutterDartProject` to run. | ||
| */ | ||
| - (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)projectOrNil; | ||
| - (nonnull instancetype)initWithName:(nonnull NSString*)labelPrefix project:(nullable FlutterDartProject*)projectOrNil; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-[NSObject init] is actually not decorated with nonnull but should be assumed to be nonnull. So unless this initializer actually returns null in some cases (common enough, see -[NSCoding initWithCoder:]) or it's baseclass designated initializer can return null, you can assume nonnull.
| */ | ||
| - (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)projectOrNil; | ||
| - (instancetype)initWithName:(NSString*)labelPrefix | ||
| project:(nullable FlutterDartProject*)projectOrNil; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be projectOrNil anymore? Can it become project?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would be a breaking change, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think a parameter name change would be breaking. The method signature would stay the same (though the implementation parameter name should be changed too).
Whatever @xster wants to do is fine though. I would have LGTM with nit except for the nullable on weak.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ohh because this is just the name used within the method, not the name that's public. got it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yup, sg. This OrNil pattern is all over the codebase, but I kept it to FlutterEngine for now.
| * of the Dart program's execution. | ||
| */ | ||
| @property(nonatomic, weak) FlutterViewController* viewController; | ||
| @property(nonatomic, weak, nullable) FlutterViewController* viewController; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe weak is always nullable even inside NS_ASSUME_NONNULL_BEGIN, you don't need to decorate this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah good to know, thanks
| #include "FlutterPlugin.h" | ||
| #include "FlutterTexture.h" | ||
|
|
||
| NS_ASSUME_NONNULL_BEGIN |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move NS_ASSUME_NONNULL_BEGIN to after the @class forward declaration. I'm not actually sure if it matters but that seems to be the pattern? Whatever you think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I have no preference.
| * Callers must use `-[FlutterEngine initWithName:project:]`. | ||
| */ | ||
| - (instancetype)init NS_UNAVAILABLE; | ||
| - (nullable instancetype)init NS_UNAVAILABLE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't need nullable here. -[NSObject init] can be assumed nonnull.
| - (nullable instancetype)init NS_UNAVAILABLE; | ||
|
|
||
| + (instancetype)new NS_UNAVAILABLE; | ||
| + (nullable instancetype)new NS_UNAVAILABLE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or here.
18b5147 to
63999d8
Compare
xster
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for reviewing
jmagman
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
No description provided.