Skip to content

proposal: protoc-gen-go: support embedding a nested type #192

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

Closed
phifty opened this issue Jun 13, 2016 · 7 comments
Closed

proposal: protoc-gen-go: support embedding a nested type #192

phifty opened this issue Jun 13, 2016 · 7 comments
Labels
generator-proto-option involves generators respecting a proto option to control generated source output proposal

Comments

@phifty
Copy link

phifty commented Jun 13, 2016

Given the code

synatx = "proto3";

package test;

message Password {
    string hash = 1;
    string salt = 2;
}
message User {
    Password password = 1;
}

The generated User struct contains than a pointer to a password struct. Is it possible to embed the struct? The User would contain the Password (without a pointer) and the Password would be initialized along with the User.

@zombiezen
Copy link
Contributor

This isn't possible with the current code generator. Protobuf schemas are independent of language, so it would be difficult to specify the semantics you want in a language-neutral way.

@phifty
Copy link
Author

phifty commented Jun 15, 2016

I would be fine with a language-specific option. Something like Password password = 1 [go_embed=true];.

@Xopherus
Copy link

what sort of use case would this be used for @phifty?

@sarbash
Copy link

sarbash commented Aug 29, 2017

At least to provide automatic binding with chi.Render

sendRequest := &mailer.SendRequest{
	Sender: &mailer.Sender{},
	Mail:   &mailer.Mail{},
}
if err := render.Bind(r, sendRequest); err != nil {}

@travisjeffery
Copy link

travisjeffery commented Sep 20, 2017

I wrote the plugin to support struct embedding: #430

@dsnet dsnet added the proposal label Dec 6, 2017
@dsnet dsnet changed the title Embed nested type? proposal: protoc-gen-go: support embedding a nested type Feb 13, 2018
@dsnet
Copy link
Member

dsnet commented Mar 8, 2018

Adding support for embedding in the mainline proto repo breaks the semantics of protobufs. According to the proto language spec, there is a distinction between the zero value for a message and an unset message (even for proto3). Embedding provides no such distinctions.

@dsnet dsnet added the generator-proto-option involves generators respecting a proto option to control generated source output label Mar 10, 2018
@dsnet
Copy link
Member

dsnet commented Mar 13, 2018

We're going to reject this for the following reasons:

1) Embedded values violates the semantics of protos.

It is unclear in this proposal whether the OP intended for Password to be embedded or *Password. If the former, then we have to reject this proposal since it violates the semantics of zero-vs-unset messages in protos. I spoke to the protobuf team and we will maintain a hard stance on that requirement.

2) Embedded pointers lead to brittle code.

Suppose that the intended behavior was the later (i.e., *Password), then this leads to brittle code as it is trivial for someone to do User.Salt without realizing that this can result in a nil-pointer derefence on User.Password, which isn't visible in the expression. It's annoying enough with Foo.Bar where you need to consciously think whether Foo is nil or not. It's even worse when you need to think about whether some intermediate de-reference that is not even visible may be nil.

3) Embedding forwards unintended methods.

When you embed T, all of the methods of T are forwarded to the parent. This is often problematic. For example, #256 and #210 proposes that users to specify whether magic methods like MarshalJSON should be generated on a per-message basis. Those two proposals have a much higher chance of being accepted. However, they would interact badly with this since T.MarshalJSON would get forwarded to the Parent if the Parent did not define its own MarshalJSON method. This is almost certainly not the desired behavior.

4) Embedding in Go creates portability issues over time. Imagine the following:

type Parent struct {
    Username
    other.pkg.Bar
}
type Username struct { Name, Pass string }

var p Parent
p.Name = "dsnet"

This may work fine today, but can run into compilation issue when the Bar type (which is outside your control) adds a Name field. For this reason, the Go1 compatibility agreement actually recommends against embedded types.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
generator-proto-option involves generators respecting a proto option to control generated source output proposal
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants