protobuf
protobuf copied to clipboard
Question: how generate nestd message field?
// example message
message t1 {
string b = 1;
}
message c {
t1 c1 = 1;
string c2 = 2;
}
// load go struct by generate
type C struct {
*T1 `protobuf:"bytes,1,opt,name=c1"`
C2 string ...
}
type T1 {
B string ...
}
no option to ignore name field. https://github.com/protocolbuffers/protobuf-go/blob/fb0abd915897428ccfdd6b03b48ad8219751ee54/cmd/protoc-gen-go/internal_gengo/main.go#L425-L427
could add nestd option on FieldOptions?
type FieldOptions struct {
....
Nestd *bool
}
const (
....
Default_FieldOptions_Nestd = bool(false)
)
func (x *FieldOptions) GetNestd() bool {
if x != nil && x.Nestd!= nil {
return *x.Nestd
}
return Default_FieldOptions_Nestd
}
Altering the FieldOptions type would require a proposal upstream to the main protobuf group: https://github.com/protocolbuffers/protobuf
Oh, I think I understand what you’re trying to do. You want to have something like:
type S1 struct{
Foo int
}
type S2 struct{
S1
Bar int
}
Unfortunately, such a concept does not really exist in protobuf. The protobuf is not a golang-data-type description language, but rather a portable language-neutral interchange format. As such, there are many semantics specific to protobuf that we are forced to comply with, even if if they are non-ideal for Golang, and we try to stick as tightly to the given semantics as we can.
As an example, we added the json tag before other languages, because it was so easy to do in Golang, but then when a JSON mapping was actually formally codified, we were suddenly out-of-spec, and had to redo how we encoded our JSON. Because of the pain caused in this situation, we’re quite shy towards unilaterally expanding the protobuf spec like this would require.
Altering the
FieldOptionstype would require a proposal upstream to the main protobuf group: https://github.com/protocolbuffers/protobufOh, I think I understand what you’re trying to do. You want to have something like:
type S1 struct{ Foo int } type S2 struct{ S1 Bar int }Unfortunately, such a concept does not really exist in protobuf. The protobuf is not a golang-data-type description language, but rather a portable language-neutral interchange format. As such, there are many semantics specific to protobuf that we are forced to comply with, even if if they are non-ideal for Golang, and we try to stick as tightly to the given semantics as we can.
As an example, we added the
jsontag before other languages, because it was so easy to do in Golang, but then when a JSON mapping was actually formally codified, we were suddenly out-of-spec, and had to redo how we encoded our JSON. Because of the pain caused in this situation, we’re quite shy towards unilaterally expanding the protobuf spec like this would require.
hello @puellanivis , thk reply.
FieldOptions is just a suggestion. Of course, if it is modified to the protocol itself, it is not a good suggestion. Everyone knows that this involves too much. However, nestd is a feature of go itself. I feel that it has nothing to do with the protobuf protocol. Nestd does not violate the protocol formulated by protobuf. Code generate can comply with the protobuf protocol. The characteristics of the language itself can still be customized. Changes in syntactic sugar.
The json int64 feature you said is really painful, it already involves the protocol specification, and the protocol itself should be followed instead of the compatible language. This is no problem.
The idea came from wanting to make nestd struct auto implement some interface, like kubernetes metadata field
// pb by generate https://github.com/kubernetes/kubernetes/blob/25a3274a4f62be0d37937c069007cedb3116e467/staging/src/k8s.io/api/core/v1/generated.proto#L3017-L3021
// go struct https://github.com/kubernetes/kubernetes/blob/25a3274a4f62be0d37937c069007cedb3116e467/staging/src/k8s.io/api/core/v1/types.go#L3962-L3967
Of course here is go struct to generate pb instead of pb generating go struct, but it's a good example.
Annotating fields to change the Go representation of them is currently not supported, and we don't plan to support it. A common approach to alleviate this is to wrap the proto types with some type that exposes the interface you want.
Annotating fields to change the Go representation of them is currently not supported, and we don't plan to support it. A common approach to alleviate this is to wrap the proto types with some type that exposes the interface you want.
hi @aktau, thk reply. Why don't you want to support it? It doesn't confuse the protocol itself, and it doesn't create ambiguity for other languages. Just for go, there are many ways to implement my idea. It's also very fast, but it will be very twisted. Your method is also one of them.
It is also a good way to provide a tpl mechanism without polluting pb, https://entgo.io/docs/templates @aktau @puellanivis
The generated code does not need to be changed, and the redundant code is generated by the user himself
So, you’re actually incorrect. Nesting structs will lose some semantics of the protobuf representation, because messages are presence sensing. That is Foo: &pb.Foo{} is different from Foo: nil even though both will return all the same values when using bar.Foo.GetField().
I understand that nesting structs a common Go language feature, but it is not compatible with the strict protobuf semantics, and this is the official protobuf library, and thus must stick to the standards themselves.
I very much understand the frustration of there being features of Go that just aren’t possible to replicate in protobuf, but that is just how life is when using with a language-independent protocol format. We cannot fit every language with all its features, we must strictly adhere to the protobuf spec.
What semantics are lost? This example is not very straightforward. Post some official explicit documentation and valid code examples to clarify which semantics are violated, thk. @puellanivis
Given:
// example message
message t1 {
string b = 1;
}
message c {
t1 c1 = 1;
string c2 = 2;
}
You can tell the difference between the protowire encoded 0A 00 12 03 66 6F 6F and 12 03 66 6F 6F. The former encodes &pb.C{ C1: &pb.T1{}; C2: "foo" } and the later encodes &pb.C{ C2: "foo" }. That presence needs to be tracked in order to properly maintain round-trippability. It’s difficult to tell just what kind of subtle difference the two have, as individuals can build their own pragmatics on top of the semantics of a message appearing empty, and a message not appearing at all. And we have to be widely compatible with any pragmatics someone might put into that protobuf semantic.
Regardless of the question of protobuf semantics, the design philosophy of the generated protobuf API is to provide a consistent representation of each protobuf language concept. Supporting multiple representations of a construct (such as choosing between an explicitly named field or an embedded one, or giving a Go field a name different from the protobuf field name) is not, in general, a design goal..
Given:
// example message message t1 { string b = 1; } message c { t1 c1 = 1; string c2 = 2; }You can tell the difference between the protowire encoded
0A 00 12 03 66 6F 6Fand12 03 66 6F 6F. The former encodes&pb.C{ C1: &pb.T1{}; C2: "foo" }and the later encodes&pb.C{ C2: "foo" }. That presence needs to be tracked in order to properly maintain round-trippability. It’s difficult to tell just what kind of subtle difference the two have, as individuals can build their own pragmatics on top of the semantics of a message appearing empty, and a message not appearing at all. And we have to be widely compatible with any pragmatics someone might put into that protobuf semantic.
@puellanivis
It's a good explanation, and it can also be directly understood by other people with similar questions. After all, this is not strongly reflected in the documentation.
thk reply.