10
votes

.proto examples all seem to start numbering their fields at one.

e.g. https://developers.google.com/protocol-buffers/docs/proto#simple

message SearchRequest {
  required string query = 1;
  optional int32 page_number = 2;
  optional int32 result_per_page = 3;
}

If zero can be used, it will make some messages one or more bytes smaller (i.e. those with a one or more field numbers of 16).

As the key is simply a varint encoding of (fieldnum << 3 | fieldtype) I can't immediately see why zero shouldn't be used.

Is there a reason for not starting the field numbering at zero?

2
I was about to do this question because we as a programers are used to start at zero. Thanks for asking!Sericaia

2 Answers

7
votes

One very immediate reason is that zero field numbers are rejected by protoc:

test.proto:2:28: Field numbers must be positive integers.

As to why Protocol Buffers has been designed this way, I can only guess. One nice consequence of this is that a message full of zeros will be detected as invalid. It can also be used to indicate "no field" internally as a return value in protocol buffers implementation.

5
votes

Assigning Tags

As you can see, each field in the message definition has a unique numbered tag. These tags are used to identify your fields in the message binary format, and should not be changed once your message type is in use. Note that tags with values in the range 1 through 15 take one byte to encode, including the identifying number and the field's type (you can find out more about this in Protocol Buffer Encoding). Tags in the range 16 through 2047 take two bytes. So you should reserve the tags 1 through 15 for very frequently occurring message elements. Remember to leave some room for frequently occurring elements that might be added in the future.

The smallest tag number you can specify is 1, and the largest is 229-1, or 536,870,911. You also cannot use the numbers 19000 through 19999 (FieldDescriptor::kFirstReservedNumber through FieldDescriptor::kLastReservedNumber), as they are reserved for the Protocol Buffers implementation - the protocol buffer compiler will complain if you use one of these reserved numbers in your .proto. Similarly, you cannot use any previously reserved tags.

https://developers.google.com/protocol-buffers/docs/proto

Just like the document says, 0 can't be detected.