-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support Optionals as Optional Parameters in the Constructor #159
Conversation
Regeneration of Djinni records causes most of the changes in this PR. The actual changes are in the following:
|
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.
Let a few comments. The main things to look again is
- Java setters need to respect nonnull
- Check whether we are double copying mutable objc members
- Currently Composer is still an internal project so no need to mention it in the PR description.
I also don't see any changes in the TypeScript generator, does that mean our TS output is already good?
- Optional behavior will be able to be switched via a usage flag for each platform. | ||
- A new [deriving method](https://github.com/dropbox/djinni#derived-methods) specifier will be implemented so that individual records can still require all parameters | ||
|
||
### Deriving Record |
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.
Section title is a bit confusing. How about "Requiring optional parameters in individual records"?
@Nonnull | ||
public String getContent() { | ||
return mContent; | ||
} | ||
|
||
public void setContent(String content) { |
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.
content is not null, we need to guard it like in the constructor, otherwise we opens a loophole to allow nulls slipping into nonnull fields.
We didn't need to guard primitives earlier because they can't be null. But String can.
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.
To be clear, @nonnull
should be added to setters of required variables, however it is not necessary for setters of optionals
|
||
@property (nonatomic, readonly, nonnull) NSString * content; | ||
@property (nonatomic, copy, nonnull) NSString * content; |
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.
do we still need to generate [content copy];
in the constructor body now that the property itself is copy
? We definitely don't want to double copy the string.
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.
Did some research and TLDR yes.
The initializer sets variables directly and bypasses their properties. Therefore the copy annotation is required in both places.
The test failure is because we have a CI step that checks when code generator is modified, all generated code is regenerated in test suite, example and benchmark. |
For the last point, yes typescript already operates like we want. When the parameter is marked as optional, it isn't required for initialization |
Problem Statement
Required optionals within the Djinni constructors presents a twofold problem.
Firstly, the developer experience when interacting with Djinni is inconsistent. Optionals are not required in typescript constructors, but are required in all other constructors. Fields are settable in C++ and typescript, but not in Java and Objective C. We should strive to have a consistent developer experience when working with optionals across any language-barrier code.
Secondly, as records become larger and used in more places, each additional optional parameter creates an increasingly problematic cascade of build errors. This can be partly mitigated by the use of builders for individual records, but builders still require updating with every record change, whether optional or not.
Changes to heavily touched records delay projects by cascades of changes required to support any single Djinni record change. These cascading changes should not be required. This PR does the following:
Changes at a High Level
copy
property for objCLegacy Record Behavior
The following compiler flags will return record behavior to legacy (readonly, all parameters required) for C++/ObjC/Java:
Deriving Record
Any record can be made to have all parameters be required by specifying it as a
req
deriving record:Omitting Convenience Constructors
Extra convenience constructors which require all parameters can be removed from optional ObjC records with a new compiler flag:
Tests
New tests are added to ensure optional behavior is correct. These tests generate new Djinni records which show how code can be generated for different permutations of optional and required parameters in a Djinni record.
Most changes in this PR come from new record file generation, and current optional record updates.