Skip to content
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

Impossible to distinguish the oneof fields from non-oneof fields when creating/using a generated class instance. #875

Open
s0nerik opened this issue Sep 28, 2023 · 4 comments

Comments

@s0nerik
Copy link

s0nerik commented Sep 28, 2023

Imagine looking at the following factory constructor (and the available properties) of a generated class:

factory FormEntry({
  $core.String? name,
  StaticTextField? staticText,
  TextInputField? textInput,
})
...
StaticTextField get staticText => $_getN(1);
TextInputField get textInput => $_getN(2);

Can I specify both the staticText and textInput at the same time? Looks like yes.

In reality, though, I can't, since it corresponds to the following protobuf:

message FormEntry {
  string name = 1;
  oneof field {
    StaticTextField static_text = 100;
    TextInputField text_input = 101;
  }
}

Notice how the generated class structure differs from protobuf, making it look like the staticText and textInput are simple fields that can both exist at the same time.

Using only the generated code (without thoroughly looking into its .proto source), it seems to be impossible to figure out if certain fields belong to a oneof group or not.

@sigurdm
Copy link
Collaborator

sigurdm commented Sep 28, 2023

If you look at the specification https://protobuf.dev/programming-guides/proto3/#oneof

Oneof fields are like regular fields except all the fields in a oneof share memory, and at most one field can be set at the same time. Setting any member of the oneof automatically clears all the other members. You can check which value in a oneof is set (if any) using a special case() or WhichOneof() method, depending on your chosen language.

So really in the interface they look like normal fields. The special semantics is when setting:

Note that if multiple values are set, the last set value as determined by the order in the proto will overwrite all previous ones.

So if you pass in multiple values in the constructor only one will end up being set. Don't do that.

How would you have expected oneofs to be represented? If Dart had some kind of union-types it could perhaps be modeled nicer in the constructor interface.

@s0nerik
Copy link
Author

s0nerik commented Sep 28, 2023

How would you have expected oneofs to be represented? If Dart had some kind of union-types it could perhaps be modeled nicer in the constructor interface.

I would imagine something like this to be possible to represent in Dart 3 via sealed classes. Generated classes could look something like this:

class FormEntry {
  factory FormEntry({
    $core.String? name,
    FormEntry_Field? field,
  })
  ...
  FormEntry_Field? get field => ...;
}

sealed class FormEntry_Field {}
class FormEntry_Field_StaticText extends FormEntry_Field {
  factory FormEntry_Field_StaticText({
    StaticTextField? staticText,
  })
  ...
  StaticTextField get staticText => ...;
}
class FormEntry_Field_TextInput extends FormEntry_Field {
  factory FormEntry_Field_TextInput({
    TextInputField? textInput,
  })
  ...
  TextInputField get textInput => ...;
}

@mahmuto
Copy link

mahmuto commented Mar 12, 2024

I was just searching around whether generating sealed classes has been implemented and came across this issue. I think it's a great idea.

@mcmah309
Copy link

mcmah309 commented Apr 29, 2024

I think a better title for this issue would be "Change oneof To Generate sealed Types".

prost (Protocol buffers for rust) does this with the Rust enum type which is essentially sealed types in Dart. I agree with the representation in @s0nerik last comment or something similar.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants