-
Notifications
You must be signed in to change notification settings - Fork 15.6k
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 TryGetExtension API (with TryGetOption) #7282
Add TryGetExtension API (with TryGetOption) #7282
Conversation
/// Gets the value of the specified extension. | ||
/// Unlike <see cref="IExtendableMessage{T}.GetExtension{TValue}(Extension{T, TValue})"/>, this doesn't return the default value for the extension if it's not set. | ||
/// </summary> | ||
bool TryGetExtension<TValue>(Extension<T, TValue> extension, out TValue value); |
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 looks like the GetExtension method was a mistake from the very beginning, since it doesn't allow simple handling of the case where the extension is not present (which is a very common case in practice).
The problem seems to be that ExtensionSet.Get returns default(T) if the value is not found, which makes it impossible to distinguish the case where extension is not present at all vs where extension is present, but is set to the default value. (e.g for int, bool, float, etc..)
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 problem seems to be that ExtensionSet.Get returns default(T) if the value is not found,
It returns the default value of the field which I believe matches up with get methods in other implementations.
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.
Can you provide and example how this is handled e.g. in java?
How can I distinguish between the extension value not being present at all from extension value being present, but set to its default value? Unless I'm missing something, it really feels that the API should allow you to do that. (does e.g. java allow that?).
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 file scope
optional int32 bar = 99999 [default = 3];
// default
int value = msg.getExtension(FooFile.Bar); // 3
msg.setExtension(FooFile.Bar, 3);
if (msg.hasExtension(FooFile.Bar)) { // true
value = msg.getExtension(FooFile.Bar); // 3
}
Custom options don't work the same way for us since java has builders and readers so they can just return the descriptor options reader and get the same API. We could add a HasOption
API, but TryGet fixes the need for that.
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. Ok so to me it looks like we basically have two ways of handling this:
-
introduce TryGetExtension method, at which point GetOption becomes pretty much useless (because it can return default value for an extension that isn't present, which seems semantically wrong), but the issue is we already have introduced GetExtension, so getting rid of it shortly after introducing is odd.
-
we can keep GetExtension (because it already exists) and introduce a new HasExtension method which allows checking whether the value is present or not. If GetExtension() is called for a value that is not present, we can throw / return the default value (what the is getExtension method's behavior in java?).
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.
getExtension
returns the default value.
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.
Ok, I didn't notice that we already have a "HasExtension" method so my last comment is partially wrong.
Because we already have the HasExtension/GetExtension pair, I don't think we need TryGetExtension at all (why increase the API surface if all the necessary functionality is already there?).
In terms of options, I think both GetOption and TryGetOption are unnecessary and we should get rid of them. See my PR: #7434
/// <summary> | ||
/// Gets a single value enum value option for this descriptor | ||
/// </summary> | ||
public bool TryGetOption<T>(Extension<EnumValueOptions, T> extension, out T value) |
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.
Adding this method is basically just duplicating the Extension API and we should avoid that.
See #7434 and let me know what you think.
Superseded by #7434 (and GetOption API is now obsolete). |
Do you think we could still use the |
I think we should have either "GetExtension and HasExtension" or "TryGetExtension" model, not both. We should try to keep the API surface as small as possible. |
Adds: