Protobuf: Oneof keyword in generated code is unsupported

Created on 9 May 2015  路  13Comments  路  Source: golang/protobuf

Aka: https://developers.google.com/protocol-buffers/docs/proto3#oneof

Specifically: protos including oneof do produce working .pb.proto files, but there doesn't seem to be any of the useful bits of Oneof implemented (selecting on which field is set, setting a field resetting the rest).

I'm sure this is being tracked internally somewhere, but I thought it would be useful to have an external issue for it for people to watch.

Most helpful comment

@tiancaiamao Go now supports oneof. We've written a reference document on how the Go protocol buffer compiler generates these, and how to use them: https://developers.google.com/protocol-buffers/docs/reference/go-generated#oneof

All 13 comments

We decided not to implement specific Go changes for oneof. It's a feature that simply doesn't fit well with Go.

Should this be added to the README then? How do you recommend distinguishing between field values if they could all legitimately contain a zero value (say, where I would want to render the data in a web page)? e.g.

message Foo {
  oneof value {
    int64 int_val;
    string string_val;
  }
}

How would I distinguish:

Foo {int_val: 0}

from

Foo {string_val: ""}

AFAIK all the other supported languages would allow this distinction in some way or another?

I would also like to know the answer to this.

This looks like a problem - the value proposition of protocol buffers is that they are completely language-agnostic... This isn't a corner case, it's a component of the language specs that won't work on a language.

Why not use empty interfaces and type switches here?

message Foo {
  oneof value {
    int64 int_val;
    string string_val;
  }
}
switch f := foo.(type) {
case int64:
  // do stuff
case string:
  // do stuff
}

This seems the the most idiomatic solution, and it prevents assigning multiple values concurrently.

Whoa, that DOES sound like a pretty solid idea... So basically the oneof field would have a type interface{}?

Yeah. You lose some type safety (ie, you could assign anything to it), and I guess there's an edge case around multiple variants of the same type with different names.

Yeah, that's true. It does assume that all subfields in the oneof have distinct types (which is probably the majority use case, but proto3 doesn't assert that it must be the case).

We have a design that we're working through now. It's unfortunately more complicated than your suggestion out of necessity.

Awesome! This is fantastic, thank you :).

Great design choice (tagged-union interface) btw. type-select casting looks very natural.

AppEngine SDK has the old version of the package bundled; if you try to import github.com/golang/protobuf it loads the old code without this commit even if you have the new code vendored in your project. I have manually downloaded this lib; copied it inside go_appengine/goroot/src; removed the old .a compiled file and goapp install github.com/golang/protobuf to generate it again. Now it works correctly.

There is a simpler way of updating/vendoring protobuf in the AppEngine devserver?

How far did we go now? Will it be supported in the future or never be supported?
I have a .proto file contain oneof, is there any temporary solution.

@tiancaiamao Go now supports oneof. We've written a reference document on how the Go protocol buffer compiler generates these, and how to use them: https://developers.google.com/protocol-buffers/docs/reference/go-generated#oneof

Was this page helpful?
0 / 5 - 0 ratings