Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
Add null checks to GetOption #7130
Add null checks to GetOption #7130
Changes from 1 commit
6143428
5609c03
30cd2d4
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
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 returning
default(T)
is a good idea. It seems that for e.g. extension of type int, you won't be able to differentiate between the option not being present at all (which should return null) and the option having value of 0.Given that the GetOption API is relatively new (and looks like it has been kind of broken for the very beginning), should we just introduce TryGetOption methods instead, to keep the semantics clean?
the GetOption can either be removed (that should be fine because it was only introduced as part of the proto2 work and we've marked proto2 support as "experimental") or it can just throw an exception if the value is not present (which renders it not very useful, so we might wanna mark it as obsolete?).
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.
Returning
default(T)
is a mistake. It should be the default value for the extension.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.
Still, even if you return
extension.DefaultValue
, it is unclear to me how I would distinguish between 1. the option not being present at all and 2. the option being present and being set to the default value (AFAIK options/extensions don't need to have default values).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 can't, which is why #7282 was made. Should we also add a
HasOption
API to go with 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.
actually, looking at the whole options API in protobuf C# from a more high level perspective, we only need to check whether
options == null
because e.g. the FileDescriptor doesn't provide access to the file options (the property FileDescriptor.Proto is internal, so one cannot access to FileDescriptor.Proto.Options).This actually has several downsides:
This makes me think that the whole GetOptions() and TryGetOption() API is a bad idea and we should rather focus on how to expose the descriptor.Options property safely, because then we wouldn't need to worry about the GetOptions/TryGetOptions etc. API's at all (they could be removed and everyone could just rely on standard extension APIs).
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 only way we could expose descriptor.Options safely is by deep cloning it (since all the protos are supposed to be immutable). With these APIs the only thing we need to clone is the value, if we need to clone it at all.
C++ has const references, Java has readers, and Python parses a local options value (but allows mutation).
Maybe we could do it like Python but, again, we'd still clone the whole options message once for every unique descriptor on get.
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.
Maybe the deep clone isn't really all that problematic. Most projects would only have a few options in place and it seems fair to require users to cache the results they got from e.g. messageDescriptor.Options if they wanted to process a large number of options.
It seems to me that just exposing description.Options (as a defensive copy) would lead to a more logical and straightforward API (with smaller footprint and fewer duplications, and also more similar to what other languages do) - WDYT?
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.
Could we make a internal wrapper class that exposes the IExtendableMessage API but only implements the pure functions? Then GetOptions would just return an IExtendableMessage implementation.
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.
But you actually want to be able to access e.g. the FileOptions' properties (the "standard" options, such as "java_package" etc.)
see
protobuf/csharp/src/Google.Protobuf/Reflection/Descriptor.cs
Line 3955 in 4059c61