Field types

There are 6 field types in Protocol Buffers:

  • Optional
  • Required
  • Implicit
  • Repeated
  • Oneof
  • Map

Every field is one of those types.

Optional

An optional field is a field that may or may not have a value set. When no value is set, this is indicated as null in Mouse Melon.

  • Proto 2

    optional string name = 1;

    In Proto 2 it is possible to give a default value to optional fields:

    optional string name = 1; [default = "bla"]

    When parsing data, the Protocol Buffer library will use this default value when no value is set.

  • Proto 3

    The optional keyword was initially not in proto 3, but came back in version 3.15.

    optional string name = 1;
  • Edition 2023

    In edition 2023, the optional keyword disappeared and fields are optional by default.

    string name = 1;

Required

An required field is similar to an optional field, except that it must be present in the serialized data. If it is not, parsing will fail. (In Mouse Melon parsing will not fail when a required field is missing in the data, but a warning icon will notify the user of the missing field)

  • Proto 2

    required string name = 1;
  • Proto 3

    Required fields are not supported in proto 3. Use an optional or implicit field instead.

  • Edition 2023

    In edition 2023, the required keyword disappeared. Required fields can still be made using the following syntax:

    string name = 1 [features.field_presence = LEGACY_REQUIRED];

Implicit

An implicit field is a field with a certain default value:

  • For numeric types and enums: 0
  • For booleans: false
  • For strings: empty string
  • For bytes: empty byte array
  • For messages: null

When a message is parsed, fields that are not present in the data will get this default value. When a message is saved, field that have this default value will not be written.

An implicit message field behaves the same as an optional message field. To emphasize that this field can be null, an implicit message field is always displayed as optional field in Mouse Melon.

  • Proto 2

    Implicit fields are not supported in proto 2. Use an optional or required field instead.

  • Proto 3

    string name = 1;
  • Edition 2023

    In edition 2023, implicit fields can be made using the following syntax:

    string name = 1 [features.field_presence = IMPLICIT];

Repeated

A repeated field is what would be called a list or array in most programming languages. It's default value is the empty list.

repeated string names = 1;

Arrays of arrays are not supported in Protocol Buffers. If you need an array of arrays, put a repeated field in a message and repeat that message. When you have a two-dimensional (rectangular) array, you can also save the flattened array and add an int field with either the width or the height of the array.

If your data type is numeric, boolean or an enum, repeated fields come in two encodings: packed and expanded. Expanded was the initial format, but the packed format saves data more efficiently. Use the packed format unless you need compatibility with very old Protocol Buffers libraries that do not support it. Modern Protocol Buffer libraries should be able to read both packed and expanded data regardless of whether the field is declared as packed or expanded in the proto file. The choice between packed and expanded is only about how the field is saved.

  • Proto 2

    In Proto 2, fields are expanded by default. To use packed fields, use this notation:

    repeated uint32 ids = 1 [packed = true];
  • Proto 3

    In Proto 3, fields are packed by default. To use expanded fields, use this notation:

    repeated uint32 ids = 1 [packed = false];
  • Edition 2023

    In edition 2023, fields are packed by default. To use expanded fields, use this notation:

    repeated uint32 ids = 1 [features.repeated_field_encoding = EXPANDED];

Oneof

With oneof you can give a list of fields. At most one of those fields can be set.

This example gives a client the possibility to log in using either a user ID or a user name:

message Login {
  oneof user {
    uint32 user_id = 1;
    string user_name = 2;
  }
  string password = 3;
}

Map

A map is a collection of key/value pairs, where each key occurs at most once. In Protocol Buffers, integers, booleans and strings can be used as map key. Any data type can be used as map value. Example:

map<string, uint32> counters = 1;

Combing field types

Field types cannot be combined, so it's not possible to have something like a repeated map or a map of maps. If you need such a combination, you'll have to wrap the inner type in a message. For repeated maps, this becomes:

message MyMap {
  map<string, string> data = 1;
}

repeated MyMap maps = 1;