proto3 non-optional field presence effects message equality, hash code
- Dominant language
- Dart
- Stars
- 572
- Forks
- 196
- Avg merge
- 1h 59m
- Merged PRs (30d)
- 2
Description
References for proto3 `optional` syntax:
- https://github.com/protocolbuffers/protobuf/blob/main/docs/implementing_proto3_presence.md
- https://github.com/protocolbuffers/protobuf/blob/main/docs/field_presence.md
Quoting the second reference above:
> The no presence serialization discipline results in visible differences from the explicit presence tracking discipline, when the default value is set. For a singular field with numeric, enum, or string type:
>
> * No presence discipline:
> ...
> The default value may mean:
> * the field was explicitly set to its default value, which is valid in the application-specific domain of values;
> * the field was notionally "cleared" by setting its default; or
> * the field was never set.
In addition, it says
> Without the optional label, proto3 APIs do not track presence for basic types (numeric, string, bytes, and enums), either
So in proto3, without `optional`, a field with default value cannot be distinguished from the non-presence of the same field. In all cases the value of the field is the default one, and presence of the field is not tracked.
With all this information, as a user, I would expect a message with default `int32` value, and a message with the field non-present to be equal, and generate the same hash code, as the difference should not be observed. This currently does not hold:
```
// field tag is 9
var m1 = Msg1()..mergeFromBuffer([72, 0]);
var m2 = Msg1()..mergeFromBuffer([]);
print('hash codes equal = ${m1.hashCode == m2.hashCode}');
print('values equal = ${m1 == m2}');
```
Output:
```
hash codes equal = false
values equal = false
```
We also generate a hazzer for this field, and it works as if the field was `optional`. That's also a bug, but I think an separate one. For example, we could be generating hazzers and track presence, but without using the hazzer the messages could be identical (i.e. equal, with same hash code, all other API methods returning the same values).
b/134058565
Contributor guide
Research direction
Start with the generated Dart message equality and hash-code behavior for the Msg1 proto3 field, then reproduce the issue's mergeFromBuffer examples. Done means a default-valued non-optional field and an absent field compare equal and produce the same hash code; treat hazzer generation as a separate issue.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- dart
- Domain
- api
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100