Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the purpose of ProtoMessage method?

when I generate go code from a protocol buffer file, I noticed that each of the generated structs implement the Message interface, https://github.com/golang/protobuf/blob/master/proto/lib.go#L277

For an example of the code that is generated, see https://github.com/google/go-genproto/blob/master/googleapis/rpc/status/status.pb.go#L97

Clearly, the other methods on Message interface, String() and Reset(), have an obvious purpose and the concrete implementation example makes that clear. However, I don't understand the purpose of the ProtoMessage() method. The method takes no parameters and returns no arguments, so why is it there?

like image 523
thurt Avatar asked Dec 17 '17 16:12

thurt


People also ask

Why is Protobuf used?

Protocol buffers provide a language-neutral, platform-neutral, extensible mechanism for serializing structured data in a forward-compatible and backward-compatible way. It's like JSON, except it's smaller and faster, and it generates native language bindings.

How efficient is Protobuf?

Google made this protocol open source and now it provides support, out of the box, to the most common languages, like JavaScript, Java, C#, Ruby and others. In our tests, it was demonstrated that this protocol performed up to 6 times faster than JSON. "Protobuf performs up to 6 times faster than JSON."

How does Protobuf encoding work?

Protobuf categorizes normally used data types into wire types which provides information to find the length of the value. For wire type 2, length is also encoded along with value. Zero values are not transmitted. 0, False, “”, does not take any bytes.

How does Protobuf encode data?

A protocol buffer message is a series of key-value pairs. The binary version of a message just uses the field's number as the key -- the name and declared type for each field can only be determined on the decoding end by referencing the message type's definition (that is, the . proto file).


1 Answers

Quoting from official doc: Protocol Buffers: Go Generated Code:

Given a simple message declaration:

message Foo {}

the protocol buffer compiler generates a struct called Foo. A *Foo implements the Message interface. See the inline comments for more information.

type Foo struct {
}

// Reset sets the proto's state to default values.
func (m *Foo) Reset()         { *m = Foo{} }

// String returns a string representation of the proto.
func (m *Foo) String() string { return proto.CompactTextString(m) }

// ProtoMessage acts as a tag to make sure no one accidentally implements the
// proto.Message interface.
func (*Foo) ProtoMessage()    {}

Note that all of these members are always present; the optimize_for option does not affect the output of the Go code generator.

This is a (similar) technique described in Go official FAQ: How can I guarantee my type satisfies an interface?

If you wish the users of an interface to explicitly declare that they implement it, you can add a method with a descriptive name to the interface's method set. For example:

type Fooer interface {
    Foo()
    ImplementsFooer()
}

A type must then implement the ImplementsFooer method to be a Fooer, clearly documenting the fact and announcing it in godoc's output.

type Bar struct{}
func (b Bar) ImplementsFooer() {}
func (b Bar) Foo() {}

Most code doesn't make use of such constraints, since they limit the utility of the interface idea. Sometimes, though, they're necessary to resolve ambiguities among similar interfaces.

So the ProtoMessage() method basically has 2 purposes:

  • The main purpose is as documented in the generated code: to make sure you don't pass a value for protobuf serialization / deserialization which otherwise (without this method) would implement the proto.Message interface but is not a "real" protobuf message value:

    ProtoMessage acts as a tag to make sure no one accidentally implements the proto.Message interface.

  • And it also documents the fact that the type is a (implements) Message. This may not have a real value at first as the code is generated and you should not bother much with it, but code analyzers and Go IDE's may make good use of it; and it also appears in generated docs.
like image 95
icza Avatar answered Oct 20 '22 21:10

icza