-
Notifications
You must be signed in to change notification settings - Fork 349
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 proto2 optional fields #139
Comments
@philikon sure, that sounds like a good idea. Thanks! |
I am using a patch of |
I looked a little bit at this, and the proto2 docs on https://developers.google.com/protocol-buffers/docs/proto#optional
So, if we have an Fwiw my guess is that users mostly expect Another option would be to have it be |
Optionals are not deserialized into default values. The reader should check if there are any bytes at the field position and if not it gets turned into the language representation of undefined. For ex in JS that's |
I mean, I agree intuitively, that's just not what the proto docs I linked to above assert... I.e. you say "turned into the language representation of Maybe the nuance is that in Scala/class-based messages, the internal field can be Dunno. I mean, I generally agree with you, and maybe we just do that anyway, even if its not technically what the docs assert (or I'm misunderstanding them). |
I believe it is. The docs say
the key words to me being that the default is set when the message does not contain an optional element for example, i am pretty sure when using just the protoc compiler with |
...so you're saying that the message would actually contain the optional element, i.e. on the wire somewhere is the data that " I.e. Fwiw that's not my understanding of how the message serialization works, i.e. a primitive is either a) included and has some set value, or b) is not included and so has no value. Can you point to docs on how to serialize/deserialize "this element/field (a primitive) is included but not set"? |
No, my understanding of it is that the readers know what the message contract is, they know what field positions to look for for bytes and whether they are optional or not, therefore the readers know that when there is nothing in a particular field position, and its an optional field, to set it to the language representation of unset, be that |
This is from the proto2 docs I linked to above: "When a message is parsed, if it does not contain an optional element, the corresponding field in the parsed object is set to the default value for that field." Which starts off sounding a lot like your "when there is nothing in a particular field position ... " except then you change to "...set it to the language representation of unset", which I can't find any description of that behavior on that proto2 page. Fwiw the java tutorial has:
Which matches my recollection of proto2 from when I used it before: the I.e my point is generally that class-based languages have two ways (methods) of accessing It's hard for ts-proto to provide two of these capabilities without something like a prototype and I just checked the Java and C++ tutorials on that page, and C++ also looks like it does the "getter is an empty string + separate hazzer method". Can you link to generated code for proto2 |
Oof 🤦 so i looked into this today and it turns out we had some patches to generators where I work that made it function as i described, but you are correct in your description of how the protobuf spec is intended to work. |
Lol, well, that explains why we were talking in circles. :-D Fwiw I get why you're are doing it that way, I personally think it makes more sense... But not sure if that means ts-proto should do it. I suppose it could end up being another option flag. |
Wanted to try and convince you to either make it optional indeed for proto2 optionals or at least provide a flag which does this. Indeed proto2 expects deserializers to return the default value when accessed directly (i.e. via getter) and add a hazzer function which checks whether the value was actually set. This is because proto2 has custom default values and these are implemented by the deserializer (which is why it can't return "undefined" if a value doesn't exist). |
@eyalpost I agree the lack of hazzers is unfortunate; I've historically gone back/forth on "would clients prefer being able to detect not-present" or "would clients prefer not having to 'or' their own default value", and kind seems like at the end-of-the-day it's going to be on a case-by-case basis. That said, I've also felt this pain in ts-proto itself, as the protobuf descriptors themselves have an If you'd like to submit a PR that changes the behavior out-right to |
@ssilve1989 can you share example how did you configure ts-proto with Bazel? |
@deser We wrote an aspect based on the one found here: https://github.com/bazelbuild/rules_nodejs/blob/4.x/packages/labs/grpc_web/ts_proto_library.bzl although aspect-based proto compilation does not look to be the recommended way of doing this anymore so we will be switching over to use an implementation by |
Thanks :) |
It would be great to have the same behavior as optionals in proto3, i.e. { scalarOptional: number | undefined } |
As a data point, I stumbled on this recently while using the descriptor generated by this library with another proto library: andrewhickman/prost-reflect#49 |
Fwiw, per an earlier update, I'm 95% sure this has been fixed b/c ts-protos own/internal |
@stephenh in my case I'm not reading the proto descriptor using this library, but I'm serializing the descriptor using this library and then consuming it from another library. |
Hm, @slinkydeveloper are you using the Lmk if you're using |
Now that we have support for proto3 optional (#73, yay!), should we also add support for proto2's version,
LABEL_OPTIONAL
? Right now something likeoptional uint32 index = 42
translates intoindex: number
but IMHO it should beindex?: number
.I'd be happy to write the code for this.
The text was updated successfully, but these errors were encountered: