# Feature Settings for Editions

Protobuf Editions features and how they affect protobuf behavior.

This topic provides an overview of the features that are included in the released edition versions. Subsequent editions’ features will be added to this topic. We announce new editions in [the News section](https://protobuf.dev/news).

Before configuring feature settings in your new schema definition content, make sure you understand why you are using them. Avoid [cargo-culting](https://protobuf.dev/best-practices/no-cargo-cults) with features.

## Prototiller

Prototiller is a command-line tool that updates proto schema configuration files between syntax versions and editions. It hasn’t been released yet, but is referenced throughout this topic.

## Features

The following sections include all of the behaviors that are configurable using features in editions. Preserving proto2 or proto3 Behavior shows how to override the default behaviors so that your proto definition files act like proto2 or proto3 files. For more information on how editions and features work together to set behavior, see [Protobuf Editions Overview](https://protobuf.dev/editions/overview).

Feature settings apply at different levels:

**File-level:** These settings apply to all elements (messages, fields, enums, and so on) that don’t have an overriding setting.

**Non-nested:** Messages, enums, and services can override settings made at the file level. They apply to everything within them (message fields, enum values) that aren’t overridden, but don’t apply to other parallel messages and enums.

**Nested:** Oneofs, messages, and enums can override settings from the message they’re nested in.

**Lowest-level:** Fields, extensions, enum values, extension ranges, and methods are the lowest level at which you can override settings.

Each of the following sections has a comment that states what scope the feature can be applied to. The following sample shows a mock feature applied to each scope:

    edition = "2024";

    // File-level scope definition
    option features.bar = BAZ;

    enum Foo {
      // Enum (non-nested scope) definition
      option features.bar = QUX;

      A = 1;
      B = 2;

    message Corge {
      // Message (non-nested scope) definition
      option features.bar = QUUX;

      message Garply {
        // Message (nested scope) definition
        option features.bar = WALDO;
        string id = 1;

      // Field (lowest-level scope) definition
      Foo A = 1 [features.bar = GRAULT];

In this example, the setting “`GRAULT"` in the lowest-level scope feature definition overrides the non-nested-scope “`QUUX`” setting. And within the Garply message, “`WALDO`” overrides “`QUUX`.”

### `features.default_symbol_visibility`

This feature enables setting the default visibility for messages and enums, making them available or unavailable when imported by other protos. Use of this feature will reduce dead symbols in order to create smaller binaries.

In addition to setting the defaults for the entire file, you can use the `local` and `export` keywords to set per-field behavior. Read more about this at [`export` / `local` Keywords](https://protobuf.dev/editions/overview#export-local).

**Values available:**

  * `EXPORT_ALL`: This is the default prior to Edition 2024. All messages and enums are exported by default.
  * `EXPORT_TOP_LEVEL`: All top-level symbols default to export; nested default to local.
  * `LOCAL_ALL`: All symbols default to local.
  * `STRICT`: All symbols local by default. Nested types cannot be exported, except for a special-case caveat for `message { enum {} reserved 0 to max; }`. This will become the default in a future edition.

**Applicable to the following scope:** file

**Added in:** Edition 2024

**Default behavior per syntax/edition:**

Syntax/edition| Default
2024| `EXPORT_TOP_LEVEL`
2023| `EXPORT_ALL`
proto3| `EXPORT_ALL`
proto2| `EXPORT_ALL`

**Note:** Feature settings on different schema elements have different scopes.

The following sample shows how you can apply the feature to elements in your proto schema definition files:

    // foo.proto
    edition = "2024";

    // Symbol visibility defaults to EXPORT_TOP_LEVEL. Setting
    // default_symbol_visibility overrides these defaults
    option features.default_symbol_visibility = LOCAL_ALL;

    // Top-level symbols are exported by default in Edition 2024; applying the local
    // keyword overrides this
    export message LocalMessage {
      int32 baz = 1;
      // Nested symbols are local by default in Edition 2024; applying the export
      // keyword overrides this
      enum ExportedNestedEnum {
        UNKNOWN_EXPORTED_NESTED_ENUM_VALUE = 0;

    // bar.proto
    edition = "2024";

    import "foo.proto";

    message ImportedMessage {
      // The following is valid because the imported message explicitly overrides
      // the visibility setting in foo.proto
      LocalMessage bar = 1;

      // The following is not valid because default_symbol_visibility is set to
      // `LOCAL_ALL`
      // LocalMessage.ExportedNestedEnum qux = 2;

### `features.enforce_naming_style`

Introduced in Edition 2024, this feature enables strict naming style enforcement as defined in [the style guide](https://protobuf.dev/programming-guides/style) to ensure protos are round-trippable by default with a feature value to opt-out to use

**Values available:**

  * `STYLE2024`: Enforces strict adherence to the style guide for naming.
  * `STYLE_LEGACY`: Applies the pre-Edition 2024 level of style guide enforcement.

**Applicable to the following scopes:** file, extension range, message, field, oneof, enum, enum value, service, method

**Added in:** Edition 2024

**Default behavior per syntax/edition:**

Syntax/edition| Default
2024| `STYLE2024`
2023| `STYLE_LEGACY`
proto3| `STYLE_LEGACY`
proto2| `STYLE_LEGACY`

**Note:** Feature settings on different schema elements have different scopes.

The following code sample shows an Edition 2023 file:

Edition 2023 defaults to `STYLE_LEGACY`, so a non-conformant field name is fine:

    edition = "2023";

    message Foo {
      // A non-conforming field name is not a problem
      int64 bar_1 = 1;

Edition 2024 defaults to `STYLE2024`, so an override is needed to keep the non-conformant field name:

    edition = "2024";

    // To keep the non-conformant field name, override the STYLE2024 setting
    option features.enforce_naming_style = STYLE_LEGACY;

    message Foo {
      int64 bar_1 = 1;

### `features.enum_type`

This feature sets the behavior for how enum values that aren’t contained within the defined set are handled. See [Enum Behavior](https://protobuf.dev/programming-guides/enum) for more information on open and closed enums.

This feature doesn’t impact proto3 files, so this section doesn’t have a before and after of a proto3 file.

**Values available:**

  * `CLOSED:` Closed enums store enum values that are out of range in the unknown field set.
  * `OPEN:` Open enums parse out of range values into their fields directly.

**Applicable to the following scopes:** file, enum

**Added in:** Edition 2023

**Default behavior per syntax/edition:**

Syntax/edition| Default
2024| `OPEN`
2023| `OPEN`
proto3| `OPEN`
proto2| `CLOSED`

**Note:** Feature settings on different schema elements have different scopes.

The following code sample shows a proto2 file:

    syntax = "proto2";

    enum Foo {
      A = 2;
      B = 4;
      C = 6;

After running Prototiller, the equivalent code might look like this:

    edition = "2024";

    enum Foo {
      // Setting the enum_type feature overrides the default OPEN enum
      option features.enum_type = CLOSED;
      A = 2;
      B = 4;
      C = 6;

### `features.field_presence`

This feature sets the behavior for tracking field presence, or the notion of whether a protobuf field has a value.

**Values available:**

  * `LEGACY_REQUIRED`: The field is required for parsing and serialization. Any explicitly-set value is serialized onto the wire (even if it is the same as the default value).
  * `EXPLICIT`: The field has explicit presence tracking. Any explicitly-set value is serialized onto the wire (even if it is the same as the default value). For singular primitive fields, `has_*` functions are generated for fields set to `EXPLICIT`.
  * `IMPLICIT`: The field has no presence tracking. The default value is not serialized onto the wire (even if it is explicitly set). `has_*` functions are not generated for fields set to `IMPLICIT`.

**Applicable to the following scopes:** file, field

**Added in:** Edition 2023

**Default behavior per syntax/edition:**

Syntax/edition| Default
2024| `EXPLICIT`
2023| `EXPLICIT`
proto3| `IMPLICIT`*
proto2| `EXPLICIT`

* proto3 is `IMPLICIT` unless the field has the `optional` label, in which case it behaves like `EXPLICIT`. See [Presence in Proto3 APIs](https://protobuf.dev/programming-guides/field_presence#presence-proto3) for more information.

**Note:** Feature settings on different schema elements have different scopes.

The following code sample shows a proto2 file:

    syntax = "proto2";

    message Foo {
      required int32 x = 1;
      optional int32 y = 2;
      repeated int32 z = 3;

After running Prototiller, the equivalent code might look like this:

    edition = "2024";

    message Foo {
      // Setting the field_presence feature retains the proto2 required behavior
      int32 x = 1 [features.field_presence = LEGACY_REQUIRED];
      int32 y = 2;
      repeated int32 z = 3;

The following shows a proto3 file:

    syntax = "proto3";

    message Bar {
      int32 x = 1;
      optional int32 y = 2;
      repeated int32 z = 3;

After running Prototiller, the equivalent code might look like this:

    edition = "2024";
    // Setting the file-level field_presence feature matches the proto3 implicit default
    option features.field_presence = IMPLICIT;

    message Bar {
      int32 x = 1;
      // Setting the field_presence here retains the explicit state that the proto3
      // field has because of the optional syntax
      int32 y = 2 [features.field_presence = EXPLICIT];
      repeated int32 z = 3;

Note that the `required` and `optional` labels no longer exist in Editions, as the corresponding behavior is set explicitly with the `field_presence` feature.

### `features.json_format`

This feature sets the behavior for JSON parsing and serialization.

This feature doesn’t impact proto3 files, so this section doesn’t have a before and after of a proto3 file. Editions behavior matches the behavior in proto3.

**Values available:**

  * `ALLOW`: A runtime must allow JSON parsing and serialization. Checks are applied at the proto level to make sure that there is a well-defined mapping to JSON.
  * `LEGACY_BEST_EFFORT`: A runtime does the best it can to parse and serialize JSON. Certain protos are allowed that can result in unspecified behavior at runtime (such as many:1 or 1:many mappings).

**Applicable to the following scopes:** file, message, enum

**Added in:** Edition 2023

**Default behavior per syntax/edition:**

Syntax/edition| Default
2024| `ALLOW`
2023| `ALLOW`
proto3| `ALLOW`
proto2| `LEGACY_BEST_EFFORT`

**Note:** Feature settings on different schema elements have different scopes.

The following code sample shows a proto2 file:

    syntax = "proto2";

    message Foo {
      // Warning only
      string bar = 1;
      string bar_ = 2;

After running Prototiller, the equivalent code might look like this:

    edition = "2024";
    option features.json_format = LEGACY_BEST_EFFORT;

    message Foo {
      string bar = 1;
      string bar_ = 2;

### `features.message_encoding`

This feature sets the behavior for encoding fields when serializing.

This feature doesn’t impact proto3 files, so this section doesn’t have a before and after of a proto3 file.

Depending on the language, fields that are “group-like” may have some unexpected capitalization in generated code and in text-format, in order to provide backwards compatibility with proto2. Message fields are “group-like” if all of the following conditions are met:

  * Has `DELIMITED` message encoding specified
  * Message type is defined in the same scope as the field
  * Field name is exactly the lowercased type name

**Values available:**

  * `LENGTH_PREFIXED`: Fields are encoded using the LEN wire type described in [Message Structure](https://protobuf.dev/programming-guides/encoding#structure).
  * `DELIMITED`: Message-typed fields are encoded as [groups](https://protobuf.dev/programming-guides/proto2#groups).

**Applicable to the following scopes:** file, field

**Added in:** Edition 2023

**Default behavior per syntax/edition:**

Syntax/edition| Default
2024| `LENGTH_PREFIXED`
2023| `LENGTH_PREFIXED`
proto3| `LENGTH_PREFIXED`
proto2| `LENGTH_PREFIXED`

**Note:** Feature settings on different schema elements have different scopes.

The following code sample shows a proto2 file:

    syntax = "proto2";

    message Foo {
      group Bar = 1 {
        optional int32 x = 1;
        repeated int32 y = 2;

After running Prototiller, the equivalent code might look like this:

    edition = "2024";

    message Foo {
      message Bar {
        int32 x = 1;
        repeated int32 y = 2;
      Bar bar = 1 [features.message_encoding = DELIMITED];

### `features.repeated_field_encoding`

This feature is what the proto2/proto3 [`packed` option](https://protobuf.dev/programming-guides/encoding#packed) for `repeated` fields has been migrated to in Editions.

**Values available:**

  * `PACKED`: `Repeated` fields of a primitive type are encoded as a single LEN record that contains each element concatenated.
  * `EXPANDED`: `Repeated` fields are each encoded with the field number for each value.

**Applicable to the following scopes:** file, field

**Added in:** Edition 2023

**Default behavior per syntax/edition:**

Syntax/edition| Default
2024| `PACKED`
2023| `PACKED`
proto3| `PACKED`
proto2| `EXPANDED`

**Note:** Feature settings on different schema elements have different scopes.

The following code sample shows a proto2 file:

    syntax = "proto2";

    message Foo {
      repeated int32 bar = 6 [packed=true];
      repeated int32 baz = 7;

After running Prototiller, the equivalent code might look like this:

    edition = "2024";
    option features.repeated_field_encoding = EXPANDED;

    message Foo {
      repeated int32 bar = 6 [features.repeated_field_encoding=PACKED];
      repeated int32 baz = 7;

The following shows a proto3 file:

    syntax = "proto3";

    message Foo {
      repeated int32 bar = 6;
      repeated int32 baz = 7 [packed=false];

After running Prototiller, the equivalent code might look like this:

    edition = "2024";

    message Foo {
      repeated int32 bar = 6;
      repeated int32 baz = 7 [features.repeated_field_encoding=EXPANDED];

### `features.utf8_validation`

This feature sets how strings are validated. It applies to all languages except where there’s a language-specific `utf8_validation` feature that overrides it. See `features.(pb.java).utf8_validation` for the Java-language-specific feature.

This feature doesn’t impact proto3 files, so this section doesn’t have a before and after of a proto3 file.

**Values available:**

  * `VERIFY`: The runtime should verify UTF-8. This is the default proto3 behavior.
  * `NONE`: The field behaves like an unverified `bytes` field on the wire. Parsers may handle this type of field in an unpredictable way, such as replacing invalid characters. This is the default proto2 behavior.

**Applicable to the following scopes:** file, field

**Added in:** Edition 2023

**Default behavior per syntax/edition:**

Syntax/edition| Default
2024| `VERIFY`
2023| `VERIFY`
proto3| `VERIFY`
proto2| `NONE`

**Note:** Feature settings on different schema elements have different scopes.

The following code sample shows a proto2 file:

    syntax = "proto2";

    message MyMessage {
      string foo = 1;

After running Prototiller, the equivalent code might look like this:

    edition = "2024";

    message MyMessage {
      string foo = 1 [features.utf8_validation = NONE];

## Language-specific Features

Some features apply to specific languages, and not to the same protos in other languages. Using these features requires you to import the corresponding *_features.proto file from the language’s runtime. The examples in the following sections show these imports.

### `features.(pb.go).api_level`

**Languages:** Go

The `api_level` feature enables you to select which API version the Go protobuf plugin should generate code for. The Opaque API is the latest version of the Protocol Buffers implementation for the Go programming language. The previous version is now called Open Struct API. See the [Go Protobuf: Releasing the Opaque API](https://go.dev/blog/protobuf-opaque) blog post for an introduction.

**Values available:**

  * `API_OPEN`: The Open Struct API generates struct types that are open to direct access.
  * `API_HYBRID`: Hybrid is a step between Open and Opaque: The Hybrid API also includes accessor methods (so you can update your code), but still exports the struct fields as before. There is no performance difference; this API level only helps with the migration.
  * `API_OPAQUE`: With the Opaque API, the struct fields are hidden and can no longer be directly accessed. Instead, the new accessor methods allow for getting, setting, or clearing a field.

**Applicable to the following scopes:** message, file

**Added in:** Edition 2023

**Default behavior per syntax/edition:**

Syntax/edition| Default
2023| `API_OPEN`
2024| `API_OPAQUE`

**Note:** Feature settings on different schema elements have different scopes.

You can set the `api_level` feature starting in edition 2023:

    edition = "2023";

    import "google/protobuf/go_features.proto";

    // Remove this line after migrating the code to the Opaque API.
    option features.(pb.go).api_level = API_HYBRID;

See also: [Opaque API: Migration](https://protobuf.dev/reference/go/opaque-migration)

### `features.(pb.cpp).enum_name_uses_string_view`

**Languages:** C++

Before Edition 2024, all generated enum types provide the following function to obtain the label out of an enum value, which has some overhead to construct the `std::string` instances at runtime:

    const std::string& Foo_Name(int);

The default feature value in Edition 2024 changes this signature to return `absl::string_view` to allow for better storage decoupling and potential memory/CPU savings. If you aren’t ready to migrate, yet, you can override this to set it back to its previous behavior. See [string_view return type](https://protobuf.dev/support/migration#string_view-return-type) in the migration guide for more on this topic.

**Values available:**

  * `true`: The enum uses `string_view` for its values.
  * `false`: The enum uses `std::string` for its values.

**Applicable to the following scopes:** file, enum

**Added in:** Edition 2024

**Default behavior per syntax/edition:**

Syntax/edition| Default
2024| `true`
2023| `false`
proto3| `false`
proto2| `false`

**Note:** Feature settings on different schema elements have different scopes.

### `features.(pb.java).large_enum`

**Languages:** Java

This language-specific feature enables you to adopt new functionality that handles large enums in Java without causing compiler errors. Note that this feature replicates enum-like behavior but has some notable differences. For example, switch statements are not supported.

**Values available:**

  * `true`: Java enums will use the new functionality.
  * `false`: Java enums will continue to use Java enums.

**Applicable to the following scopes:** file, enum

**Added in:** Edition 2024

**Default behavior per syntax/edition:**

Syntax/edition| Default
2024| `false`
2023| `false`
proto3| `false`
proto2| `false`

**Note:** Feature settings on different schema elements have different scopes.

### `features.(pb.cpp/pb.java).legacy_closed_enum`

**Languages:** C++, Java

This feature determines whether a field with an open enum type should be behave as if it was a closed enum. This allows editions to reproduce [non-conformant behavior](https://protobuf.dev/programming-guides/enum) in Java and C++ from proto2 and proto3.

This feature doesn’t impact proto3 files, and so this section doesn’t have a before and after of a proto3 file.

**Values available:**

  * `true`: Treats the enum as closed regardless of `enum_type`.
  * `false`: Respect whatever is set in the `enum_type`.

**Applicable to the following scopes:** file, field

**Added in:** Edition 2023

**Default behavior per syntax/edition:**

Syntax/edition| Default
2024| `false`
2023| `false`
proto3| `false`
proto2| `true`

**Note:** Feature settings on different schema elements have different scopes.

The following code sample shows a proto2 file:

    syntax = "proto2";

    import "myproject/proto3file.proto";

    message Msg {
      myproject.proto3file.Proto3Enum name = 1;

After running Prototiller, the equivalent code might look like this:

    edition = "2024";

    import "myproject/proto3file.proto";

    import "google/protobuf/cpp_features.proto";
    import "google/protobuf/java_features.proto";

    message Msg {
      myproject.proto3file.Proto3Enum name = 1 [
        features.(pb.cpp).legacy_closed_enum = true,
        features.(pb.java).legacy_closed_enum = true
      ];

### `features.(pb.java).nest_in_file_class`

**Languages:** Java

This feature controls whether the Java generator will nest the generated class in the Java generated file class. Setting this option to `NO` is the equivalent of setting `java_multiple_files = true` in proto2/proto3/edition 2023.

The default outer classname is also updated to always be the camel-cased .proto filename suffixed with Proto by default (for example, `foo/bar_baz.proto` becomes `BarBazProto`). You can still override this using the `java_outer_classname` file option and replace the pre-Edition 2024 default of `BarBaz` or `BarBazOuterClass` depending on the presence of conflicts.

**Values available:**

  * `NO`: Do not nest the generated class in the file class.
  * `YES`: Nest the generated class in the file class.
  * Legacy: Nesting behavior controlled by `java_multiple_files` option (see go/java-proto-names#immutable-api-message-names).

**Applicable to the following scopes:** message, enum, service

**Added in:** Edition 2024

**Default behavior per syntax/edition:**

Syntax/edition| Default
2024| `NO`
2023| Legacy
proto3| Legacy
proto2| Legacy

**Note:** Feature settings on different schema elements have different scopes.

### `features.(pb.cpp).string_type`

**Languages:** C++

This feature determines how generated code should treat string fields. This replaces the `ctype` option from proto2 and proto3, and offers a new `string_type` feature. In Edition 2023, you can specify either `ctype` or `string_type` on a field, but not both. In Edition 2024, the `ctype` option is removed.

**Values available:**

  * `VIEW`: Generates `string_view` accessors for the field.
  * `CORD`: Generates `Cord` accessors for the field. Not supported on extension fields.
  * `STRING`: Generates `string` accessors for the field.

**Applicable to the following scopes:** file, field

**Added in:** Edition 2023

**Default behavior per syntax/edition:**

Syntax/edition| Default
2024| `VIEW`
2023| `STRING`
proto3| `STRING`
proto2| `STRING`

**Note:** Feature settings on different schema elements have different scopes.

The following code sample shows a proto2 file:

    syntax = "proto2";

    message Foo {
      optional string bar = 6;
      optional string baz = 7 [ctype = CORD];

After running Prototiller, the equivalent code might look like this:

    edition = "2024";

    import "google/protobuf/cpp_features.proto";

    message Foo {
      string bar = 6 [features.(pb.cpp).string_type = STRING];
      string baz = 7 [features.(pb.cpp).string_type = CORD];

The following shows a proto3 file:

    syntax = "proto3"

    message Foo {
      string bar = 6;
      string baz = 7 [ctype = CORD];

After running Prototiller, the equivalent code might look like this:

    edition = "2024";

    import "google/protobuf/cpp_features.proto";

    message Foo {
      string bar = 6 [features.(pb.cpp).string_type = STRING];
      string baz = 7 [features.(pb.cpp).string_type = CORD];

### `features.(pb.java).utf8_validation`

**Languages:** Java

This language-specific feature enables you to override the file-level settings at the field level for Java only.

This feature doesn’t impact proto3 files, and so this section doesn’t have a before and after of a proto3 file.

**Values available:**

  * `DEFAULT`: The behavior matches that set by `features.utf8_validation`.
  * `VERIFY`: Overrides the file-level `features.utf8_validation` setting to force it to `VERIFY` for Java only.

**Applicable to the following scopes:** file, field

**Added in:** Edition 2023

**Default behavior per syntax/edition:**

Syntax/edition| Default
2024| `DEFAULT`
2023| `DEFAULT`
proto3| `DEFAULT`
proto2| `DEFAULT`

**Note:** Feature settings on different schema elements have different scopes.

The following code sample shows a proto2 file:

    syntax = "proto2";

    option java_string_check_utf8=true;

    message MyMessage {
      string foo = 1;
      string bar = 2;

After running Prototiller, the equivalent code might look like this:

    edition = "2024";

    import "google/protobuf/java_features.proto";

    option features.utf8_validation = NONE;
    option features.(pb.java).utf8_validation = VERIFY;
    message MyMessage {
      string foo = 1;
      string bar = 2;

### `features.(pb.go).strip_enum_prefix`

**Languages:** Go

Enum values are not scoped by their containing enum name, so [prefixing every value with the enum name is recommended](https://protobuf.dev/programming-guides/style#enums):

    edition = "2024";

    enum Strip {
      STRIP_ZERO = 0;
      STRIP_ONE = 1;

However, the generated Go code will now contain two prefixes!

    type Strip int32

    const (
        Strip_STRIP_ZERO Strip = 0
        Strip_STRIP_ONE  Strip = 1
    )

The language-specific `strip_enum_prefix` feature determines whether the Go code generator strips the repetitive prefix or not.

**Values available:**

  * `STRIP_ENUM_PREFIX_KEEP`: Keep the name as-is, even if repetitive.
  * `STRIP_ENUM_PREFIX_GENERATE_BOTH`: Generate both, a full name and a stripped name (to help with migrating your Go code).
  * `STRIP_ENUM_PREFIX_STRIP`: Strip the enum name prefix from enum value names.

**Applicable to the following scopes:** file, enum, enum value

**Added in:** Edition 2024

**Default behavior per syntax/edition:**

Syntax/edition| Default
2024| `STRIP_ENUM_PREFIX_KEEP`

**Note:** Feature settings on different schema elements have different scopes.

You can set the `strip_enum_prefix` feature in edition 2024 (or newer) .proto files:

    edition = "2024";

    import "google/protobuf/go_features.proto";

    option features.(pb.go).strip_enum_prefix = STRIP_ENUM_PREFIX_STRIP;

    enum Strip {
      STRIP_ZERO = 0;
      STRIP_ONE = 1;

The generated Go code will now strip the `STRIP` prefix:

    type Strip int32

    const (
        Strip_ZERO Strip = 0
        Strip_ONE  Strip = 1
    )

## Preserving proto2 or proto3 Behavior in Edition 2023

You may want to move to the editions format but not deal with updates to the way that generated code behaves yet. This section shows the changes that the Prototiller tool makes to your .proto files to make edition-2023-based protos behave like a proto2 or proto3 file.

After these changes are made at the file level, you get the proto2 or proto3 defaults. You can override at lower levels (message level, field level) to consider additional behavior differences (such as required, proto3 optional) or if you want your definition to only be _mostly_ like proto2 or proto3.

We recommend using Prototiller unless you have a specific reason not to. To manually apply all of these instead of using Prototiller, add the content from the following sections to the top of your .proto file.

### Proto2 Behavior

The following shows the settings to replicate proto2 behavior with Edition 2023.

    edition = "2023";

    import "google/protobuf/cpp_features.proto";
    import "google/protobuf/java_features.proto";

    option features.field_presence = EXPLICIT;
    option features.enum_type = CLOSED;
    option features.repeated_field_encoding = EXPANDED;
    option features.json_format = LEGACY_BEST_EFFORT;
    option features.utf8_validation = NONE;
    option features.(pb.cpp).legacy_closed_enum = true;
    option features.(pb.java).legacy_closed_enum = true;

### Proto3 Behavior

The following shows the settings to replicate proto3 behavior with Edition 2023.

    edition = "2023";

    import "google/protobuf/cpp_features.proto";
    import "google/protobuf/java_features.proto";

    option features.field_presence = IMPLICIT;
    option features.enum_type = OPEN;
    // `packed=false` needs to be transformed to field-level repeated_field_encoding
    // features in Editions syntax
    option features.json_format = ALLOW;
    option features.utf8_validation = VERIFY;
    option features.(pb.cpp).legacy_closed_enum = false;
    option features.(pb.java).legacy_closed_enum = false;

### Edition 2023 to 2024

The following shows the settings to replicate Edition 2023 behavior with Edition 2024.

    // foo/bar_baz.proto
    edition = "2024";

    import option "third_party/protobuf/cpp_features.proto";
    import option "third_party/java/protobuf/java_features.proto";
    import option "third_party/golang/protobuf/v2/src/google/protobuf/go_features.proto";

    // If previously relying on edition 2023 default java_outer_classname.
    option java_outer_classname = "BarBaz" // or BarBazOuterClass

    option features.(pb.cpp).string_type = STRING;
    option features.enforce_naming_style = STYLE_LEGACY;
    option features.default_symbol_visibility = EXPORT_ALL;
    option features.(pb.cpp).enum_name_uses_string_view = false;
    option features.(pb.go).api_level = API_OPEN;

    message MyMessage {
      option features.(pb.java).nest_in_file_class = YES;

### Caveats and Exceptions

This section shows the changes that you’ll need to make manually if you choose not to use Prototiller.

Setting the file-level defaults shown in the previous section sets the default behaviors in most cases, but there are a few exceptions.

**Edition 2023 and later**

  * `optional`: Remove all instances of the `optional` label and change the `features.field_presence` to `EXPLICIT` if the file default is `IMPLICIT`.
  * `required`: Remove all instances of the `required` label and add the `features.field_presence=LEGACY_REQUIRED` option at the field level.
  * `groups`: Unwrap the `groups` into a separate message and add the `features.message_encoding = DELIMITED` option at the field level. See `features.message_encoding` for more on this.
  * `java_string_check_utf8`: Remove this file option and replace it with the `features.(pb.java).utf8_validation`. You’ll need to import Java features, as covered in Language-specific Features.
  * `packed`: For proto2 files converted to editions format, remove the `packed` field option and add `[features.repeated_field_encoding=PACKED]` at the field level when you don’t want the `EXPANDED` behavior that you set in Proto2 Behavior. For proto3 files converted to editions format, add `[features.repeated_field_encoding=EXPANDED]` at the field level when you don’t want the default proto3 behavior.

**Edition 2024 and later**

  * (C++) `ctype`: Remove all instances of the `ctype` option and set the `features.(pb.cpp).string_type` value.
  * (C++ and Go) `weak`: Remove weak importsimports.. Use [`import option`](https://protobuf.dev/editions/overview#import-option) instead.
  * (Java) `java_multiple_files`: Remove `java_multiple_files` and use `features.(pb.java).nest_in_file_class` instead.


# Objective-C Generated Code Guide

Describes exactly what Objective-C code the protocol buffer compiler generates for any given protocol definition.

Any differences between proto2, proto3, and Editions generated code are highlighted. You should read the [proto2 language guide](https://protobuf.dev/programming-guides/proto2) and/or [proto3 language guide](https://protobuf.dev/programming-guides/proto3) and/or the [Editions guide](https://protobuf.dev/programming-guides/editions) before reading this document.

## Compiler invocation

The protocol buffer compiler produces Objective-C output when invoked with the `--objc_out=` command-line flag. The parameter to the `--objc_out=` option is the directory where you want the compiler to write your Objective-C output. The compiler creates a header file and an implementation file for each `.proto` file input. The names of the output files are computed by taking the name of the `.proto` file and making the following changes:

  * The file name is determined by converting the `.proto` file base name to camel case. For example, `foo_bar.proto` will become `FooBar`.
  * The extension (`.proto`) is replaced with either `pbobjc.h` or `pbobjc.m` for the header or implementation file, respectively.
  * The proto path (specified with the `--proto_path=` or `-I` command-line flag) is replaced with the output path (specified with the `--objc_out=` flag).

So, for example, if you invoke the compiler as follows:

    protoc --proto_path=src --objc_out=build/gen src/foo.proto src/bar/baz.proto

The compiler will read the files `src/foo.proto` and `src/bar/baz.proto` and produce four output files: `build/gen/Foo.pbobjc.h`, `build/gen/Foo.pbobjc.m`, `build/gen/bar/Baz.pbobjc.h`, and `build/gen/bar/Baz.pbobjc.m`. The compiler will automatically create the directory `build/gen/bar` if necessary, but it will _not_ create `build` or `build/gen`; they must already exist.

## Packages

The Objective-C code generated by the protocol buffer compiler is completely unaffected by the package name defined in the `.proto` file, as Objective-C has no language-enforced namespacing. Instead, Objective-C class names are distinguished using prefixes, which you can find out about in the next section.

## Class prefix

Given the following [file option](https://protobuf.dev/programming-guides/proto3#options):

    option objc_class_prefix = "CGOOP";

The specified string - in this case, `CGOOP` \- is prefixed in front of all Objective-C classes generated for this `.proto` file. Use prefixes that are 3 or more characters as recommended by Apple. Note that all 2 letter prefixes are reserved by Apple.

## Camel case conversion

Idiomatic Objective-C uses camel case for all identifiers.

Messages will not have their names converted because the standard for proto files is to name messages in camel case already. It is assumed that the user has bypassed the convention for good reason, and the implementation will conform with their intentions.

Methods generated from field names and `oneof`s, `enum` declarations, and extension accessors will have their names camel cased. In general to convert from a proto name to a camel cased Objective-C name:

  * The first letter converted to uppercase (except for fields, which always start with a lowercase letter).
  * For each underscore in the name, the underscore is removed, and the following letter is capitalized.

So, for example, the field `foo_bar_baz` becomes `fooBarBaz`. The field `FOO_bar` becomes `fooBar`.

## Messages

Given a simple message declaration:

    message Foo {}

The protocol buffer compiler generates a class called `Foo`. If you specify an `objc_class_prefix` file option, the value of this option is prepended to the generated class name.

In the case of outer messages that have names matching any C/C++ or Objective-C keywords:

    message static {}

the generated interfaces are suffixed by `_Class`, as follows:

    @interface static_Class {}

Note that as per the camel case conversion rules the name `static` is _not_ converted. In the case of an inner message that has a camel cased name that is `FieldNumber` or `OneOfCase`, the generated interface will be the camel cased name suffixed by `_Class` to make sure that the generated names do not conflict with the `FieldNumber` enumerations or `OneOfCase` enumerations.

A message can also be declared inside another message.

    message Foo {
      message Bar {}

This generates:

    @interface Foo_Bar : GPBMessage
    @end

As you can see, the generated nested message name is the name of the generated containing message name (`Foo`) appended with underscore (`_`) and the nested message name (`Bar`).

> **Note:** While we have tried to ensure that conflicts are kept to a minimum, there are still potential cases where message names may conflict due to the conversion between underscores and camel case. As an example:
>     message foo_bar {}
>     message foo { message bar {} }
> will both generate `@interface foo_bar` and will conflict. The most pragmatic solution may be to rename the conflicting messages.

### `GPBMessage` interface

`GPBMessage` is the superclass of all generated message classes. It is required to support a superset of the following interface:

    @interface GPBMessage : NSObject
    @end

The behaviors for this interface are as follows:

    // Will do a deep copy.
    - (id)copy;
    // Will perform a deep equality comparison.
    - (BOOL)isEqual:(id)value;

### Unknown fields

When a message is parsed, it may contain fields that are not known to the parsing code. This can happen when a message is created with an [older version](https://protobuf.dev/programming-guides/proto2#updating) of a .proto definition and is then parsed with code generated from a newer version (or vice versa).

These fields are not discarded and are stored in the message’s `unknownFields` property:

    @property(nonatomic, copy, nullable) GPBUnknownFieldSet *unknownFields;

You can use the `GPBUnknownFieldSet` interface to fetch these fields by number or loop over them as an array.

## Fields

The following sections describe the code generated by the protocol buffer compiler for message fields. They are divided by those with implicit and explicit presence. You can learn more about this distinction in [Field Presence](https://protobuf.dev/programming-guides/field_presence).

### Singular Fields with Implicit Presence

For every singular field the compiler generates a property to store data and an integer constant containing the field number. Message type fields also get a `has..` property that lets you check if the field is set in the encoded message. So, for example, given the following message:

    message Foo {
      message Bar {
        int32 int32_value = 1;
      enum Qux {...}
      int32 int32_value = 1;
      string string_value = 2;
      Bar message_value = 3;
      Qux enum_value = 4;
      bytes bytes_value = 5;

The compiler will generate the following:

    typedef GPB_ENUM(Foo_Bar_FieldNumber) {
      // The generated field number name is the enclosing message names delimited by
      // underscores followed by "FieldNumber", followed by the field name
      // camel cased.
      Foo_Bar_FieldNumber_Int32Value = 1,
    };

    @interface Foo_Bar : GPBMessage
    @property(nonatomic, readwrite) int32_t int32Value;
    @end

    typedef GPB_ENUM(Foo_FieldNumber) {
      Foo_FieldNumber_Int32Value = 1,
      Foo_FieldNumber_StringValue = 2,
      Foo_FieldNumber_MessageValue = 3,
      Foo_FieldNumber_EnumValue = 4,
      Foo_FieldNumber_BytesValue = 5,
    };

    typedef GPB_ENUM(Foo_Qux) {
      Foo_Qux_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
      ...
    };

    @interface Foo : GPBMessage
    // Field names are camel cased.
    @property(nonatomic, readwrite) int32_t int32Value;
    @property(nonatomic, readwrite, copy, null_resettable) NSString *stringValue;
    @property(nonatomic, readwrite) BOOL hasMessageValue;
    @property(nonatomic, readwrite, strong, null_resettable) Foo_Bar *messageValue;
    @property(nonatomic, readwrite) Foo_Qux enumValue;
    @property(nonatomic, readwrite, copy, null_resettable) NSData *bytesValue;
    @end

#### Special naming cases

There are cases where the field name generation rules may result in name conflicts and names will need to be "uniqued". Such conflicts are resolved by appending `_p` to the end of the field (`_p` was selected because it’s pretty unique, and stands for "property").

    message Foo {
      int32 foo_array = 1;      // Ends with Array
      int32 bar_OneOfCase = 2;  // Ends with oneofcase
      int32 id = 3;             // Is a C/C++/Objective-C keyword

generates:

    typedef GPB_ENUM(Foo_FieldNumber) {
      // If a non-repeatable field name ends with "Array" it will be suffixed
      // with "_p" to keep the name distinct from repeated types.
      Foo_FieldNumber_FooArray_p = 1,
      // If a field name ends with "OneOfCase" it will be suffixed with "_p" to
      // keep the name distinct from OneOfCase properties.
      Foo_FieldNumber_BarOneOfCase_p = 2,
      // If a field name is a C/C++/ObjectiveC keyword it will be suffixed with
      // "_p" to allow it to compile.
      Foo_FieldNumber_Id_p = 3,
    };

    @interface Foo : GPBMessage
    @property(nonatomic, readwrite) int32_t fooArray_p;
    @property(nonatomic, readwrite) int32_t barOneOfCase_p;
    @property(nonatomic, readwrite) int32_t id_p;
    @end

#### Default values

The [default value](https://protobuf.dev/programming-guides/proto3#default) for numeric types is `0`.

The default value for strings is `@""`, and the default value for bytes is `[NSData data]`.

Assigning `nil` to a string field will assert in debug, and set the field to `@""` in release. Assigning `nil` to a bytes field will assert in debug and set the field to `[NSData data]` in release. To test whether a bytes or string field is set requires testing its length property and comparing it to 0.

The default "empty" value for a message is an instance of the default message. To clear a message value it should be set to `nil`. Accessing a cleared message will return an instance of the default message and the `hasFoo` method will return false.

The default message returned for a field is a local instance. The reason behind returning a default message instead of `nil` is that in the case of:

    message Foo {
      message Bar {
         int32 b;
      Bar a;

The implementation will support:

    Foo *foo = [[Foo alloc] init];
    foo.a.b = 2;

where `a` will be automatically created via the accessors if necessary. If `foo.a` returned `nil`, the `foo.a.b` setter pattern would not work.

### Singular Fields with Explicit Presence

For every singular field the compiler generates a property to store data, an integer constant containing the field number, and a `has..` property that lets you check if the field is set in the encoded message. So, for example, given the following message:

    message Foo {
      message Bar {
        int32 int32_value = 1;
      enum Qux {...}
      optional int32 int32_value = 1;
      optional string string_value = 2;
      optional Bar message_value = 3;
      optional Qux enum_value = 4;
      optional bytes bytes_value = 5;

The compiler will generate the following:

    # Enum Foo_Qux

    typedef GPB_ENUM(Foo_Qux) {
      Foo_Qux_Flupple = 0,
    };

    GPBEnumDescriptor *Foo_Qux_EnumDescriptor(void);

    BOOL Foo_Qux_IsValidValue(int32_t value);

    # Message Foo

    typedef GPB_ENUM(Foo_FieldNumber) {
      Foo_FieldNumber_Int32Value = 2,
      Foo_FieldNumber_MessageValue = 3,
      Foo_FieldNumber_EnumValue = 4,
      Foo_FieldNumber_BytesValue = 5,
      Foo_FieldNumber_StringValue = 6,
    };

    @interface Foo : GPBMessage

    @property(nonatomic, readwrite) BOOL hasInt32Value;
    @property(nonatomic, readwrite) int32_t int32Value;

    @property(nonatomic, readwrite) BOOL hasStringValue;
    @property(nonatomic, readwrite, copy, null_resettable) NSString *stringValue;

    @property(nonatomic, readwrite) BOOL hasMessageValue;
    @property(nonatomic, readwrite, strong, null_resettable) Foo_Bar *messageValue;

    @property(nonatomic, readwrite) BOOL hasEnumValue;
    @property(nonatomic, readwrite) Foo_Qux enumValue;

    @property(nonatomic, readwrite) BOOL hasBytesValue;
    @property(nonatomic, readwrite, copy, null_resettable) NSData *bytesValue;

    @end

    # Message Foo_Bar

    typedef GPB_ENUM(Foo_Bar_FieldNumber) {
      Foo_Bar_FieldNumber_Int32Value = 1,
    };

    @interface Foo_Bar : GPBMessage

    @property(nonatomic, readwrite) BOOL hasInt32Value;
    @property(nonatomic, readwrite) int32_t int32Value;

    @end

#### Special naming cases

There are cases where the field name generation rules may result in name conflicts and names will need to be "uniqued". Such conflicts are resolved by appending `_p` to the end of the field (`_p` was selected because it’s pretty unique, and stands for "property").

    message Foo {
      optional int32 foo_array = 1;      // Ends with Array
      optional int32 bar_OneOfCase = 2;  // Ends with oneofcase
      optional int32 id = 3;             // Is a C/C++/Objective-C keyword

generates:

    typedef GPB_ENUM(Foo_FieldNumber) {
      // If a non-repeatable field name ends with "Array" it will be suffixed
      // with "_p" to keep the name distinct from repeated types.
      Foo_FieldNumber_FooArray_p = 1,
      // If a field name ends with "OneOfCase" it will be suffixed with "_p" to
      // keep the name distinct from OneOfCase properties.
      Foo_FieldNumber_BarOneOfCase_p = 2,
      // If a field name is a C/C++/ObjectiveC keyword it will be suffixed with
      // "_p" to allow it to compile.
      Foo_FieldNumber_Id_p = 3,
    };

    @interface Foo : GPBMessage
    @property(nonatomic, readwrite) int32_t fooArray_p;
    @property(nonatomic, readwrite) int32_t barOneOfCase_p;
    @property(nonatomic, readwrite) int32_t id_p;
    @end

#### Default values (optional fields only)

The [default value](https://protobuf.dev/programming-guides/proto2#optional) for numeric types, if no explicit default was specified by the user, is `0`.

The default value for strings is `@""`, and the default value for bytes is `[NSData data]`.

Assigning `nil` to a string field will assert in debug, and set the field to `@""` in release. Assigning `nil` to a bytes field will assert in debug and set the field to `[NSData data]` in release. To test whether a bytes or string field is set requires testing its length property and comparing it to 0.

The default "empty" value for a message is an instance of the default message. To clear a message value it should be set to `nil`. Accessing a cleared message will return an instance of the default message and the `hasFoo` method will return false.

The default message returned for a field is a local instance. The reason behind returning a default message instead of `nil` is that in the case of:

    message Foo {
      message Bar {
         int32 b;
      Bar a;

The implementation will support:

    Foo *foo = [[Foo alloc] init];
    foo.a.b = 2;

where `a` will be automatically created via the accessors if necessary. If `foo.a` returned `nil`, the `foo.a.b` setter pattern would not work.

### Repeated fields

Like singular fields (proto2 proto3), the protocol buffer compiler generates one data property for each repeated field. This data property is a `GPB<VALUE>Array` depending on the field type where `<VALUE>` can be one of `UInt32`, `Int32`, `UInt64`, `Int64`, `Bool`, `Float`, `Double`, or `Enum`. `NSMutableArray` will be used for `string`, `bytes` and `message` types. Field names for repeated types have `Array` appended to them. The reason for appending `Array` in the Objective-C interface is to make the code more readable. Repeated fields in proto files tend to have singular names which do not read well in standard Objective-C usage. Making the singular names plural would be more idiomatic Objective-C, however pluralization rules are too complex to support in the compiler.

    message Foo {
      message Bar {}
      enum Qux {}
      repeated int32 int32_value = 1;
      repeated string string_value = 2;
      repeated Bar message_value = 3;
      repeated Qux enum_value = 4;

generates:

    typedef GPB_ENUM(Foo_FieldNumber) {
      Foo_FieldNumber_Int32ValueArray = 1,
      Foo_FieldNumber_StringValueArray = 2,
      Foo_FieldNumber_MessageValueArray = 3,
      Foo_FieldNumber_EnumValueArray = 4,
    };

    @interface Foo : GPBMessage
    // Field names for repeated types are the camel case name with
    // "Array" suffixed.
    @property(nonatomic, readwrite, strong, null_resettable)
     GPBInt32Array *int32ValueArray;
    @property(nonatomic, readonly) NSUInteger int32ValueArray_Count;

    @property(nonatomic, readwrite, strong, null_resettable)
     NSMutableArray *stringValueArray;
    @property(nonatomic, readonly) NSUInteger stringValueArray_Count;

    @property(nonatomic, readwrite, strong, null_resettable)
     NSMutableArray *messageValueArray;
    @property(nonatomic, readonly) NSUInteger messageValueArray_Count;

    @property(nonatomic, readwrite, strong, null_resettable)
     GPBEnumArray *enumValueArray;
    @property(nonatomic, readonly) NSUInteger enumValueArray_Count;
    @end

**Note:** The behavior of repeated fields can be configured in Editions with the [`features.repeated_field_encoding` feature](https://protobuf.dev/editions/features#repeated_field_encoding).

For string, bytes and message fields, elements of the array are `NSString*`, `NSData*` and pointers to subclasses of `GPBMessage` respectively.

#### Default values

The [default value](https://protobuf.dev/programming-guides/proto3#default) for a repeated field is to be empty. In Objective-C generated code, this is an empty `GPB<VALUE>Array`. If you access an empty repeated field, you’ll get back an empty array that you can update like any other repeated field array.

    Foo *myFoo = [[Foo alloc] init];
    [myFoo.stringValueArray addObject:@"A string"]

You can also use the provided `<field>Array_Count` property to check if the array for a particular repeated field is empty without having to create the array:

    if (myFoo.messageValueArray_Count) {
      // There is something in the array...

#### `GPB<VALUE>Array` interface

`GPB<VALUE>Array`s (aside from `GPBEnumArray`, which we’ll look at below) have the following interface:

    @interface GPBArray : NSObject
    @property (nonatomic, readonly) NSUInteger count;
    + (instancetype)array;
    + (instancetype)arrayWithValue:()value;
    + (instancetype)arrayWithValueArray:(GPBArray *)array;
    + (instancetype)arrayWithCapacity:(NSUInteger)count;

    // Initializes the array, copying the values.
    - (instancetype)initWithValueArray:(GPBArray *)array;
    - (instancetype)initWithValues:(const  [])values
                             count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
    - (instancetype)initWithCapacity:(NSUInteger)count;

    - ()valueAtIndex:(NSUInteger)index;

    - (void)enumerateValuesWithBlock:
         (void (^)( value, NSUInteger idx, BOOL *stop))block;
    - (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
        usingBlock:(void (^)( value, NSUInteger idx, BOOL *stop))block;

    - (void)addValue:()value;
    - (void)addValues:(const  [])values count:(NSUInteger)count;
    - (void)addValuesFromArray:(GPBArray *)array;

    - (void)removeValueAtIndex:(NSUInteger)count;
    - (void)removeAll;

    - (void)exchangeValueAtIndex:(NSUInteger)idx1
                withValueAtIndex:(NSUInteger)idx2;
    - (void)insertValue:()value atIndex:(NSUInteger)count;
    - (void)replaceValueAtIndex:(NSUInteger)index withValue:()value;

    @end

`GPBEnumArray` has a slightly different interface to handle the validation function and to access raw values.

    @interface GPBEnumArray : NSObject
    @property (nonatomic, readonly) NSUInteger count;
    @property (nonatomic, readonly) GPBEnumValidationFunc validationFunc;

    + (instancetype)array;
    + (instancetype)arrayWithValidationFunction:(nullable GPBEnumValidationFunc)func;
    + (instancetype)arrayWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                       rawValue:value;
    + (instancetype)arrayWithValueArray:(GPBEnumArray *)array;
    + (instancetype)arrayWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                       capacity:(NSUInteger)count;

    - (instancetype)initWithValidationFunction:
      (nullable GPBEnumValidationFunc)func;

    // Initializes the array, copying the values.
    - (instancetype)initWithValueArray:(GPBEnumArray *)array;
    - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
        values:(const int32_t [])values
        count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
    - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                      capacity:(NSUInteger)count;

    // These will return kGPBUnrecognizedEnumeratorValue if the value at index
    // is not a valid enumerator as defined by validationFunc. If the actual
    // value is desired, use the "raw" version of the method.
    - (int32_t)valueAtIndex:(NSUInteger)index;
    - (void)enumerateValuesWithBlock:
        (void (^)(int32_t value, NSUInteger idx, BOOL *stop))block;
    - (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts
        usingBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block;

    // These methods bypass the validationFunc to provide access to values
    // that were not known at the time the binary was compiled.
    - (int32_t)rawValueAtIndex:(NSUInteger)index;

    - (void)enumerateRawValuesWithBlock:
        (void (^)(int32_t value, NSUInteger idx, BOOL *stop))block;
    - (void)enumerateRawValuesWithOptions:(NSEnumerationOptions)opts
        usingBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block;

    // If value is not a valid enumerator as defined by validationFunc, these
    // methods will assert in debug, and will log in release and assign the value
    // to the default value. Use the rawValue methods below to assign
    // non enumerator values.
    - (void)addValue:(int32_t)value;
    - (void)addValues:(const int32_t [])values count:(NSUInteger)count;
    - (void)insertValue:(int32_t)value atIndex:(NSUInteger)count;
    - (void)replaceValueAtIndex:(NSUInteger)index withValue:(int32_t)value;

    // These methods bypass the validationFunc to provide setting of values that
    // were not known at the time the binary was compiled.
    - (void)addRawValue:(int32_t)rawValue;
    - (void)addRawValuesFromEnumArray:(GPBEnumArray *)array;
    - (void)addRawValues:(const int32_t [])values count:(NSUInteger)count;
    - (void)replaceValueAtIndex:(NSUInteger)index withRawValue:(int32_t)rawValue;
    - (void)insertRawValue:(int32_t)value atIndex:(NSUInteger)count;

    // No validation applies to these methods.
    - (void)removeValueAtIndex:(NSUInteger)count;
    - (void)removeAll;
    - (void)exchangeValueAtIndex:(NSUInteger)idx1
                withValueAtIndex:(NSUInteger)idx2;

    @end

### Oneof fields

Given a message with [oneof](https://protobuf.dev/programming-guides/proto3#oneof) field definitions:

    message Order {
      oneof OrderID {
        string name = 1;
        int32 address = 2;
      };
      int32 quantity = 3;
    };

The protocol buffer compiler generates:

    typedef GPB_ENUM(Order_OrderID_OneOfCase) {
      Order_OrderID_OneOfCase_GPBUnsetOneOfCase = 0,
      Order_OrderID_OneOfCase_Name = 1,
      Order_OrderID_OneOfCase_Address = 2,
    };

    typedef GPB_ENUM(Order_FieldNumber) {
      Order_FieldNumber_Name = 1,
      Order_FieldNumber_Address = 2,
      Order_FieldNumber_Quantity = 3,
    };

    @interface Order : GPBMessage
    @property (nonatomic, readwrite) Order_OrderID_OneOfCase orderIDOneOfCase;
    @property (nonatomic, readwrite, copy, null_resettable) NSString *name;
    @property (nonatomic, readwrite) int32_t address;
    @property (nonatomic, readwrite) int32_t quantity;
    @end

    void Order_ClearOrderIDOneOfCase(Order *message);

Setting one of the oneof properties will clear all the other properties associated with the oneof.

`<ONE_OF_NAME>_OneOfCase_GPBUnsetOneOfCase` will always be equivalent to 0 to allow for easy testing to see if any field in the oneof is set.

### Map Fields

For this message definition:

    message Bar {...}
    message Foo {
      map<int32, string> a_map = 1;
      map<string, Bar> b_map = 2;
    };

The compiler generates the following:

    typedef GPB_ENUM(Foo_FieldNumber) {
      Foo_FieldNumber_AMap = 1,
      Foo_FieldNumber_BMap = 2,
    };

    @interface Foo : GPBMessage
    // Map names are the camel case version of the field name.
    @property (nonatomic, readwrite, strong, null_resettable) GPBInt32ObjectDictionary *aMap;
    @property(nonatomic, readonly) NSUInteger aMap_Count;
    @property (nonatomic, readwrite, strong, null_resettable) NSMutableDictionary *bMap;
    @property(nonatomic, readonly) NSUInteger bMap_Count;
    @end

Cases where keys are strings and values are strings, bytes, or messages are handled by `NSMutableDictionary`.

Other cases are:

    GBP<KEY><VALUE>Dictionary

where:

  * `<KEY>` is Uint32, Int32, UInt64, Int64, Bool or String.
  * `<VALUE>` is UInt32, Int32, UInt64, Int64, Bool, Float, Double, Enum, or Object. `Object` is used for values of type `string` `bytes` or `message` to cut down on the number of classes and is in line with how Objective-C works with `NSMutableDictionary`.

#### Default values

The [default value](https://protobuf.dev/programming-guides/proto3#default) for a map field is empty. In Objective-C generated code, this is an empty `GBP<KEY><VALUE>Dictionary`. If you access an empty map field, you’ll get back an empty dictionary that you can update like any other map field.

You can also use the provided `<mapField>_Count` property to check if a particular map is empty:

    if (myFoo.myMap_Count) {
      // There is something in the map...

#### `GBP<KEY><VALUE>Dictionary` interface

The `GBP<KEY><VALUE>Dictionary` (apart from `GBP<KEY>ObjectDictionary` and `GBP<KEY>EnumDictionary`) interface is as follows:

    @interface GPB<KEY>Dictionary : NSObject
    @property (nonatomic, readonly) NSUInteger count;

    + (instancetype)dictionary;
    + (instancetype)dictionaryWithValue:(const )value
                                 forKey:(const <KEY>)key;
    + (instancetype)dictionaryWithValues:(const  [])values
                                 forKeys:(const <KEY> [])keys
                                   count:(NSUInteger)count;
    + (instancetype)dictionaryWithDictionary:(GPB<KEY>Dictionary *)dictionary;
    + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;

    - (instancetype)initWithValues:(const  [])values
                           forKeys:(const <KEY> [])keys
                             count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
    - (instancetype)initWithDictionary:(GPB<KEY>Dictionary *)dictionary;
    - (instancetype)initWithCapacity:(NSUInteger)numItems;

    - (BOOL)valueForKey:(<KEY>)key value:(VALUE *)value;

    - (void)enumerateKeysAndValuesUsingBlock:
        (void (^)(<KEY> key,  value, BOOL *stop))block;

    - (void)removeValueForKey:(<KEY>)aKey;
    - (void)removeAll;
    - (void)setValue:()value forKey:(<KEY>)key;
    - (void)addEntriesFromDictionary:(GPB<KEY>Dictionary *)otherDictionary;
    @end

The `GBP<KEY>ObjectDictionary` interface is:

    @interface GPB<KEY>ObjectDictionary : NSObject
    @property (nonatomic, readonly) NSUInteger count;

    + (instancetype)dictionary;
    + (instancetype)dictionaryWithObject:(id)object
                                 forKey:(const <KEY>)key;
    + (instancetype)
      dictionaryWithObjects:(const id GPB_UNSAFE_UNRETAINED [])objects
                    forKeys:(const <KEY> [])keys
                      count:(NSUInteger)count;
    + (instancetype)dictionaryWithDictionary:(GPB<KEY>ObjectDictionary *)dictionary;
    + (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;

    - (instancetype)initWithObjects:(const id GPB_UNSAFE_UNRETAINED [])objects
                            forKeys:(const <KEY> [])keys
                              count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
    - (instancetype)initWithDictionary:(GPB<KEY>ObjectDictionary *)dictionary;
    - (instancetype)initWithCapacity:(NSUInteger)numItems;

    - (id)objectForKey:(uint32_t)key;

    - (void)enumerateKeysAndObjectsUsingBlock:
        (void (^)(<KEY> key, id object, BOOL *stop))block;

    - (void)removeObjectForKey:(<KEY>)aKey;
    - (void)removeAll;
    - (void)setObject:(id)object forKey:(<KEY>)key;
    - (void)addEntriesFromDictionary:(GPB<KEY>ObjectDictionary *)otherDictionary;
    @end

`GBP<KEY>EnumDictionary` has a slightly different interface to handle the validation function and to access raw values.

    @interface GPB<KEY>EnumDictionary : NSObject

    @property(nonatomic, readonly) NSUInteger count;
    @property(nonatomic, readonly) GPBEnumValidationFunc validationFunc;

    + (instancetype)dictionary;
    + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func;
    + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                            rawValue:(int32_t)rawValue
                                              forKey:(<KEY>_t)key;
    + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                           rawValues:(const int32_t [])values
                                             forKeys:(const <KEY>_t [])keys
                                               count:(NSUInteger)count;
    + (instancetype)dictionaryWithDictionary:(GPB<KEY>EnumDictionary *)dictionary;
    + (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                            capacity:(NSUInteger)numItems;

    - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func;
    - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                     rawValues:(const int32_t [])values
                                       forKeys:(const <KEY>_t [])keys
                                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
    - (instancetype)initWithDictionary:(GPB<KEY>EnumDictionary *)dictionary;
    - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                      capacity:(NSUInteger)numItems;

    // These will return kGPBUnrecognizedEnumeratorValue if the value for the key
    // is not a valid enumerator as defined by validationFunc. If the actual value is
    // desired, use "raw" version of the method.

    - (BOOL)valueForKey:(<KEY>_t)key value:(nullable int32_t *)value;

    - (void)enumerateKeysAndValuesUsingBlock:
        (void (^)(<KEY>_t key, int32_t value, BOOL *stop))block;

    // These methods bypass the validationFunc to provide access to values that were not
    // known at the time the binary was compiled.

    - (BOOL)valueForKey:(<KEY>_t)key rawValue:(nullable int32_t *)rawValue;

    - (void)enumerateKeysAndRawValuesUsingBlock:
        (void (^)(<KEY>_t key, int32_t rawValue, BOOL *stop))block;

    - (void)addRawEntriesFromDictionary:(GPB<KEY>EnumDictionary *)otherDictionary;

    // If value is not a valid enumerator as defined by validationFunc, these
    // methods will assert in debug, and will log in release and assign the value
    // to the default value. Use the rawValue methods below to assign non enumerator
    // values.

    - (void)setValue:(int32_t)value forKey:(<KEY>_t)key;

    // This method bypass the validationFunc to provide setting of values that were not
    // known at the time the binary was compiled.
    - (void)setRawValue:(int32_t)rawValue forKey:(<KEY>_t)key;

    // No validation applies to these methods.

    - (void)removeValueForKey:(<KEY>_t)aKey;
    - (void)removeAll;

    @end

## Enumerations

Given an enum definition like:

    enum Foo {
      VALUE_A = 0;
      VALUE_B = 1;
      VALUE_C = 5;

the generated code will be:

    // The generated enum value name will be the enumeration name followed by
    // an underscore and then the enumerator name converted to camel case.
    // GPB_ENUM is a macro defined in the Objective-C Protocol Buffer headers
    // that enforces all enum values to be int32 and aids in Swift Enumeration
    // support.
    typedef GPB_ENUM(Foo) {
      Foo_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue, //proto3 only
      Foo_ValueA = 0,
      Foo_ValueB = 1;
      Foo_ValueC = 5;
    };

    // Returns information about what values this enum type defines.
    GPBEnumDescriptor *Foo_EnumDescriptor();

Each enumeration has a validation function declared for it:

    // Returns YES if the given numeric value matches one of Foo's
    // defined values (0, 1, 5).
    BOOL Foo_IsValidValue(int32_t value);

and an enumeration descriptor accessor function declared for it:

    // GPBEnumDescriptor is defined in the runtime and contains information
    // about the enum definition, such as the enum name, enum value and enum value
    // validation function.
    typedef GPBEnumDescriptor *(*GPBEnumDescriptorAccessorFunc)();

The enum descriptor accessor functions are C functions, as opposed to methods on the enumeration class, because they are rarely used by client software. This will cut down on the amount of Objective-C runtime information generated, and potentially allow the linker to deadstrip them.

In the case of outer enums that have names matching any C/C++ or Objective-C keywords, such as:

    enum method {}

the generated interfaces are suffixed with `_Enum`, as follows:

    // The generated enumeration name is the keyword suffixed by _Enum.
    typedef GPB_ENUM(Method_Enum) {}

An enum can also be declared inside another message. For example:

    message Foo {
      enum Bar {
        VALUE_A = 0;
        VALUE_B = 1;
        VALUE_C = 5;
      Bar aBar = 1;
      Bar aDifferentBar = 2;
      repeated Bar aRepeatedBar = 3;

generates:

    typedef GPB_ENUM(Foo_Bar) {
      Foo_Bar_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue, //proto3 only
      Foo_Bar_ValueA = 0;
      Foo_Bar_ValueB = 1;
      Foo_Bar_ValueC = 5;
    };

    GPBEnumDescriptor *Foo_Bar_EnumDescriptor();

    BOOL Foo_Bar_IsValidValue(int32_t value);

    @interface Foo : GPBMessage
    @property (nonatomic, readwrite) Foo_Bar aBar;
    @property (nonatomic, readwrite) Foo_Bar aDifferentBar;
    @property (nonatomic, readwrite, strong, null_resettable)
     GPBEnumArray *aRepeatedBarArray;
    @end

    // proto3 only Every message that has an enum field will have an accessor function to get
    // the value of that enum as an integer. This allows clients to deal with
    // raw values if they need to.
    int32_t Foo_ABar_RawValue(Foo *message);
    void SetFoo_ABar_RawValue(Foo *message, int32_t value);
    int32_t Foo_ADifferentBar_RawValue(Foo *message);
    void SetFoo_ADifferentBar_RawValue(Foo *message, int32_t value);

All enumeration fields have the ability to access the value as a typed enumerator (`Foo_Bar` in the example above), or, if using proto3, as a raw `int32_t` value (using the accessor functions in the example above). This is to support the case where the server returns values that the client may not recognize due to the client and server being compiled with different versions of the proto file.

Unrecognized enum values are treated differently depending on the language version and the `features.enum_type` feature in Editions.

  * In open enums, `kGPBUnrecognizedEnumeratorValue` is returned for the typed enumerator value if the enumerator value in the parsed message data is not one that the code reading it was compiled to support. If the actual value is desired, use the raw value accessors to get the value as an `int32_t`.
  * In closed enums, unrecognized enum values are treated as unknown fields.
  * Proto2 enums are closed, and proto3 enums are open. In Editions, the behavior is configurable with the `features.enum_type` feature.

`kGPBUnrecognizedEnumeratorValue` is defined as `0xFBADBEEF`, and it will be an error if any enumerator in an enumeration has this value. Attempting to set any enumeration field to this value is a runtime error. Similarly, attempting to set any enumeration field to an enumerator not defined by its enumeration type using the typed accessors is a runtime error. In both error cases, debug builds will cause an assertion and release builds will log and set the field to its default value (`0`).

The raw value accessors are defined as C functions instead of as Objective-C methods because they are not used in most cases. Declaring them as C functions cuts down on wasted Objective-C runtime information and allows the linker to potentially dead strip them.

### Swift Enumeration Support

Apple documents how they import Objective-C enumerations to Swift enumerations in [Interacting with C APIs](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html#//apple_ref/doc/uid/TP40014216-CH8-XID_11). Protocol buffer-generated enumerations support Objective-C to Swift conversions.

    // Proto
    enum Foo {
      VALUE_A = 0;

generates:

    // Objective-C
    typedef GPB_ENUM(Foo) {
      Foo_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
      Foo_ValueA = 0,
    };

which in Swift code will allow:

    // Swift
    let aValue = Foo.ValueA
    let anotherValue: Foo = .GPBUnrecognizedEnumeratorValue

## Well-known types

If you use any of the message types provided with protocol buffers, they will in general just use their proto definitions in generated Objective-C code, though we supply some basic conversion methods in categories to make using them simpler. Note that we do not have special APIs for all well-known types yet, including [`Any`](https://protobuf.dev/programming-guides/proto3#any) (there is currently no helper method to convert an `Any`’s message value into a message of the appropriate type).

### Time Stamps

    @interface GPBTimeStamp (GPBWellKnownTypes)
    @property (nonatomic, readwrite, strong) NSDate *date;
    @property (nonatomic, readwrite) NSTimeInterval timeIntervalSince1970;
    - (instancetype)initWithDate:(NSDate *)date;
    - (instancetype)initWithTimeIntervalSince1970:
        (NSTimeInterval)timeIntervalSince1970;
    @end

### Duration

    @interface GPBDuration (GPBWellKnownTypes)
    @property (nonatomic, readwrite) NSTimeInterval timeIntervalSince1970;
    - (instancetype)initWithTimeIntervalSince1970:
        (NSTimeInterval)timeIntervalSince1970;
    @end

## Extensions (proto2 and editions only)

You can control the generation of extensions by using the `extension_generation_mode` option. There are three modes:

  * `class_based`: Generates Objective-C classes and methods for extensions (Legacy).
  * `c_function`: Generates C functions for extensions (New).
  * `migration`: Generates both.

### Class-based (Legacy)

Given a message with an [extension range](https://protobuf.dev/programming-guides/proto2#extensions):

    message Foo {
      extensions 100 to 199;

    extend Foo {
      int32 foo = 101;
      repeated int32 repeated_foo = 102;

    message Bar {
      extend Foo {
        int32 bar = 103;
        repeated int32 repeated_bar = 104;

The compiler generates the following:

    # File Test2Root

    @interface Test2Root : GPBRootObject

    // The base class provides:
    //   + (GPBExtensionRegistry *)extensionRegistry;
    // which is an GPBExtensionRegistry that includes all the extensions defined by
    // this file and all files that it depends on.

    @end

    @interface Test2Root (DynamicMethods)
    + (GPBExtensionDescriptor *)foo;
    + (GPBExtensionDescriptor *)repeatedFoo;
    @end

    # Message Foo

    @interface Foo : GPBMessage

    @end

    # Message Bar

    @interface Bar : GPBMessage

    @end

    @interface Bar (DynamicMethods)

    + (GPBExtensionDescriptor *)bar;
    + (GPBExtensionDescriptor *)repeatedBar;
    @end

To get and set these extension fields, you use the following:

    Foo *fooMsg = [[Foo alloc] init];

    // Set the single field extensions
    [fooMsg setExtension:[Test2Root foo] value:@5];
    NSAssert([fooMsg hasExtension:[Test2Root foo]]);
    NSAssert([[fooMsg getExtension:[Test2Root foo]] intValue] == 5);

    // Add two things to the repeated extension:
    [fooMsg addExtension:[Test2Root repeatedFoo] value:@1];
    [fooMsg addExtension:[Test2Root repeatedFoo] value:@2];
    NSAssert([fooMsg hasExtension:[Test2Root repeatedFoo]]);
    NSAssert([[fooMsg getExtension:[Test2Root repeatedFoo]] count] == 2);

    // Clearing
    [fooMsg clearExtension:[Test2Root foo]];
    [fooMsg clearExtension:[Test2Root repeatedFoo]];
    NSAssert(![fooMsg hasExtension:[Test2Root foo]]);
    NSAssert(![fooMsg hasExtension:[Test2Root repeatedFoo]]);

### C-functions (New)

When using `c_function` mode, C functions are generated instead of Objective-C classes. This reduces binary size and avoids name conflicts.

The naming convention for the generated functions involves the proto package and the extension name. If an `objc_class_prefix` is defined, it is prepended.

  * File-scoped registry: `<Prefix><Package>_<File>_Registry()`
  * File-scoped extension: `<Prefix><Package>_extension_<Field>()`
  * Message-scoped extension: `<Prefix><Package>_<ScopeMessage>_extension_<Field>()`

(Note: `Package` is the CamelCased proto package name. `File` is the file name. `ScopeMessage` is the message containing the extension definition.)

Using the same example as above, but assuming `package my.package;` and file `test2.proto`:

The compiler generates C functions declared in the header:

    // Registry function for the file.
    GPBExtensionRegistry *MyPackage_Test2_Registry(void);

    // File-scoped extensions.
    GPBExtensionDescriptor *MyPackage_extension_Foo(void);
    GPBExtensionDescriptor *MyPackage_extension_RepeatedFoo(void);

    // Message-scoped extensions (scoped to Bar).
    GPBExtensionDescriptor *MyPackage_Bar_extension_Bar(void);
    GPBExtensionDescriptor *MyPackage_Bar_extension_RepeatedBar(void);

To get and set these extension fields:

    Foo *fooMsg = [[Foo alloc] init];

    // Set the single field extensions
    [fooMsg setExtension:MyPackage_extension_Foo() value:@5];
    NSAssert([fooMsg hasExtension:MyPackage_extension_Foo()]);
    NSAssert([[fooMsg getExtension:MyPackage_extension_Foo()] intValue] == 5);

    // Add two things to the repeated extension:
    [fooMsg addExtension:MyPackage_extension_RepeatedFoo() value:@1];
    [fooMsg addExtension:MyPackage_extension_RepeatedFoo() value:@2];
    NSAssert([fooMsg hasExtension:MyPackage_extension_RepeatedFoo()]);
    NSAssert([[fooMsg getExtension:MyPackage_extension_RepeatedFoo()] count] == 2);

    // Clearing
    [fooMsg clearExtension:MyPackage_extension_Foo()];
    [fooMsg clearExtension:MyPackage_extension_RepeatedFoo()];
    NSAssert(![fooMsg hasExtension:MyPackage_extension_Foo()]);
    NSAssert(![fooMsg hasExtension:MyPackage_extension_RepeatedFoo()]);


# Protocol Buffer MIME Types

Standard MIME types for Protobuf Serializations.

All Protobuf documents should have the MIME type `application` and the subtype `protobuf`, with the suffix `+json` for JSON encodings according to [the standard](https://datatracker.ietf.org/doc/draft-murray-dispatch-mime-protobuf/), followed by the following parameters:

  * `encoding` should be set only to `binary`, or `json`, denoting those respective formats.
    * With subtype `protobuf+json`, `encoding` has the default `json` and cannot be set to `binary`. With subtype `protobuf` (without `+json`), `encoding` has the default `binary` and cannot be set to `json`.
    * Use `+json` for JSON even in HTTP responses that use parser breakers as a CORB mitigation.
  * Set `charset` to `utf-8` for all JSONor Text Format encodings, and never set it for binary encodings.
    * If `charset` is unspecified it is assumed to be UTF-8. It is preferable to always specify a `charset` as that may prevent certain attack vectors when protos are used in HTTP responses.
  * Protobuf reserves the `version` parameter for potential future versioning of our wire formats. Do not set it until a wire format is versioned.

So the standard MIME types for common protobuf encodings are:

  * `application/protobuf` for serialized binary protos.
  * `application/protobuf+json; charset=utf-8` for JSON format protos.

Services that read Protobuf should also handle `application/json`, which may be used to encode JSON format protos.

Parsers must fail if MIME parameters (`encoding`, `charset`, or `version`) have unknown or illegal values.

When binary protos are transacted over HTTP, Protobuf strongly recommends Base64-encoding them and setting `X-Content-Type-Options: nosniff` to prevent XSS, as it is possible for a Protobuf to parse as active content.

It is acceptable to pass additional parameters to these MIME types if desired, such as a type URL which indicates the content schema; but the MIME type parameters _**must not**_ include encoding options.


# Python Comparison

Describes how Python compares objects.

Because of how proto data is serialized, you cannot rely on the wire representation of a proto message instance to determine if its content is the same as another instance. A subset of the ways that a wire-format proto message instance can vary include the following:

  * The protobuf schema changes in certain ways.
  * A map field stores its values in a different order.
  * The binary is built with different flags (such as opt vs. debug).
  * The protobuf library is updated.

Because of these ways that serialized data can vary, determining equality involves other methods.

## Comparison Methods

You can compare protocol buffer messages for equality using the standard Python `==` operator. Comparing two objects using the `==` operator compares with `message.ListFields()`. When testing, you can use `self.assertEqual(msg1, msg2)`.

Two messages are considered equal if they have the same type and all of their corresponding fields are equal. The inequality operator `!=` is the exact inverse of `==`.

Message equality is recursive: for two messages to be equal, any nested messages must also be equal.

## Field Equality and Presence

The equality check for fields is value-based. For fields with explicit presence, the presence of a field is also taken into account.

A field that is explicitly set to its default value is **not** considered equal to a field that is unset.

For example, consider the following message which has an explicit presence field:

    edition = "2023";
    message MyMessage {
      int32 value = 1; // 'explicit' presence by default in Editions

If you create two instances, one where `value` is unset and one where `value` is explicitly set to `0`, they will not be equal:

    msg1 = MyMessage()
    msg2 = MyMessage()
    msg2.value = 0

    assert not msg1.HasField("value")
    assert msg2.HasField("value")
    assert msg1 != msg2

This same principle applies to sub-message fields: an unset sub-message is not equal to a sub-message that is present but empty (a default instance of the sub-message class).

For fields with implicit presence, since presence cannot be tracked, the field is always compared by its value against the corresponding field in the other message.

This behavior, where presence is part of the equality check, is different from how some other languages or protobuf libraries might handle equality, where unset fields and fields set to their default value are sometimes treated as equivalent (often for wire-format compatibility). In Python, `==` performs a stricter check.

## Other Field Types

  * **Repeated fields** are equal if they have the same number of elements and each corresponding element is equal. The order of elements matters.
  * **Map fields** are equal if they have the same set of key-value pairs. The order of pairs does not matter.
  * **Floating-point fields** (`float` and `double`) are compared by value. Be aware of the usual caveats with floating-point comparisons.


# PHP Generated Code Guide

Describes the PHP code that the protocol buffer compiler generates for any given protocol definition.

You should read the [proto3 language guide](https://protobuf.dev/programming-guides/proto3) or [Editions language guide](https://protobuf.dev/programming-guides/editions) before reading this document. Note that the protocol buffer compiler currently only supports proto3 and editions code generation for PHP.

## Compiler Invocation

The protocol buffer compiler produces PHP output when invoked with the `--php_out=` command-line flag. The parameter to the `--php_out=` option is the directory where you want the compiler to write your PHP output. In order to conform to PSR-4, the compiler creates a sub-directory corresponding to the package defined in the proto file. In addition, for each message in the proto file input the compiler creates a separate file in the package’s subdirectory. The names of the output files of messages are composed of three parts:

  * Base directory: The proto path (specified with the `--proto_path=` or `-I` command-line flag) is replaced with the output path (specified with the `--php_out=` flag).
  * Sub-directory: `.` in the package name are replaced by the operating system directory separator. Each package name component is capitalized.
  * File: The message name is appended by `.php`.

So, for example, let’s say you invoke the compiler as follows:

    protoc --proto_path=src --php_out=build/gen src/example.proto

And `src/example.proto` is defined as:

    edition = "2023";
    package foo.bar;
    message MyMessage {}

The compiler will read the files `src/foo.proto` and produce the output file: `build/gen/Foo/Bar/MyMessage.php`. The compiler will automatically create the directory `build/gen/Foo/Bar` if necessary, but it will _not_ create `build` or `build/gen`; they must already exist.

## Packages

The package name defined in the `.proto` file is used by default to generate a module structure for the generated PHP classes. Given a file like:

    package foo.bar;

    message MyMessage {}

The protocol compiler generates an output class with the name `Foo\Bar\MyMessage`.

### Namespace Options

The compiler supports additional options to define the PHP and metadata namespace. When defined, these are used to generate the module structure and the namespace. Given options like:

    package foo.bar;
    option php_namespace = "baz\\qux";
    option php_metadata_namespace = "Foo";
    message MyMessage {}

The protocol compiler generates an output class with the name `baz\qux\MyMessage`. The class will have the namespace `namespace baz\qux`.

The protocol compiler generates a metadata class with the name `Foo\Metadata`. The class will have the namespace `namespace Foo`.

_The options generated are case-sensitive. By default, the package is converted to Pascal case._

## Messages

Given a simple message declaration:

    message Foo {
      int32 int32_value = 1;
      string string_value = 2;
      repeated int32 repeated_int32_value = 3;
      map<int32, int32> map_int32_int32_value = 4;

The protocol buffer compiler generates a PHP class called `Foo`. This class inherits from a common base class, `Google\Protobuf\Internal\Message`, which provides methods for encoding and decoding your message types, as shown in the following example:

    $from = new Foo();
    $from->setInt32Value(1);
    $from->setStringValue('a');
    $from->getRepeatedInt32Value()[] = 1;
    $from->getMapInt32Int32Value()[1] = 1;
    $data = $from->serializeToString();
    $to = new Foo();
    try {
      $to->mergeFromString($data);
    } catch (Exception $e) {
      // Handle parsing error from invalid data.
      ...

You should _not_ create your own `Foo` subclasses. Generated classes are not designed for subclassing and may lead to "fragile base class" problems.

Nested messages result in a PHP class of the same name prefixed by their containing message and separated by underscores, as PHP doesn’t support nested classes. So, for example, if you have this in your `.proto`:

    message TestMessage {
      message NestedMessage {
        int32 a = 1;

The compiler will generate the following class:

    // PHP doesn’t support nested classes.
    class TestMessage_NestedMessage {
      public function __construct($data = NULL) {...}
      public function getA() {...}
      public function setA($var) {...}

If the message class name is reserved (for example, `Empty`), the prefix `PB` is prepended to the class name:

    class PBEmpty {...}

We have also provided the file level option `php_class_prefix`. If this is specified, it is prepended to all generated message classes.

## Fields

For each field in a message type, the protocol buffer compiler generates a set of accessor methods to set and get the field. The accessor methods are named using `snake_case` field names converted to `PascalCase`. So, given a field `field_name`, the accessor methods will be `getFieldName` and `setFieldName`.

    // optional MyEnum optional_enum
    $m->getOptionalEnum();
    $m->setOptionalEnum(MyEnum->FOO);
    $m->hasOptionalEnum();
    $m->clearOptionalEnum();

    // MyEnum implicit_enum
    $m->getImplicitEnum();
    $m->setImplicitEnum(MyEnum->FOO);

Whenever you set a field, the value is type-checked against the declared type of that field. If the value is of the wrong type (or out of range), an exception will be raised. By default type conversions (for example, when assigning a value to a field or adding an element to a repeated field) are permitted to and from integer, float, and numeric strings. Conversions that are not permitted include all conversions to/from arrays or objects. Float to integer overflow conversions are undefined.

You can see the corresponding PHP type for each scalar protocol buffers type in the [scalar value types table](https://protobuf.dev/programming-guides/proto3#scalar).

### `has...` and `clear...`

For fields with explicit presence, the compiler generates a `has...()` method. This method returns `true` if the field is set.

The compiler also generates a `clear...()` method. This method unsets the field. After calling this method, `has...()` will return `false`.

For fields with implicit presence, the compiler does not generate `has...()` or `clear...()` methods. For these fields, you can check for presence by comparing the field value with the default value.

### Singular Message Fields

For a field with a message type, the compiler generates the same accessor methods as for scalar types.

A field with a message type defaults to `null`, and is not automatically created when the field is accessed. Thus you need to explicitly create sub messages, as in the following:

    $m = new MyMessage();
    $m->setZ(new SubMessage());
    $m->getZ()->setFoo(42);

    $m2 = new MyMessage();
    $m2->getZ()->setFoo(42);  // FAILS with an exception

You can assign any instance to a message field, even if the instance is also held elsewhere (for example, as a field value on another message).

### Repeated Fields

The protocol buffer compiler generates a special `RepeatedField` for each repeated field. So, for example, given the following field:

    repeated int32 foo = 1;

The generated code lets you do this:

    $m->getFoo()[] =1;
    $m->setFoo($array);

### Map Fields

The protocol buffer compiler generates a `MapField` for each map field. So given this field:

    map<int32, int32> weight = 1;

You can do the following with the generated code:

    $m->getWeight()[1] = 1;

## Enumerations

PHP doesn’t have native enums, so instead the protocol buffer compiler generates a PHP class for each enum type in your `.proto` file, just like for messages, with constants defined for each value. So, given this enum:

    enum TestEnum {
      Default = 0;
      A = 1;

The compiler generates the following class:

    class TestEnum {
      const DEFAULT = 0;
      const A = 1;

Also as with messages, a nested enum will result in a PHP class of the same name prefixed by its containing message(s) and separated with underscores, as PHP does not support nested classes.

    class TestMessage_NestedEnum {...}

If an enum class or value name is reserved (for example, `Empty`), the prefix `PB` is prepended to the class or value name:

    class PBEmpty {
      const PBECHO = 0;

We have also provided the file level option `php_class_prefix`. If this is specified, it is prepended to all generated enum classes.

## Oneof

For a [oneof](https://protobuf.dev/programming-guides/editions#oneof), the protocol buffer compiler generates a `has` and `clear` method for each field in the oneof, as well as a special accessor method that lets you find out which oneof field (if any) is set. So, given this message:

    message TestMessage {
      oneof test_oneof {
        int32 oneof_int32 = 1;
        int64 oneof_int64 = 2;

The compiler generates the following fields and special method:

    class TestMessage {
      private oneof_int32;
      private oneof_int64;
      public function getOneofInt32();
      public function setOneofInt32($var);
      public function getOneofInt64();
      public function setOneofInt64($var);
      public function getTestOneof();  // Return field name

The accessor method’s name is based on the oneof’s name, and returns a string representing the field in the oneof that is currently set. If the oneof is not set, the method returns an empty string.

When you set a field in a oneof, it automatically clears all other fields in the oneof. If you want to set multiple fields in a oneof, you must do so in separate statements.

    $m = new TestMessage();
    $m->setOneofInt32(42); // $m->hasOneofInt32() is true
    $m->setOneofInt64(123); // $m->hasOneofInt32() is now false