> Like, should that IDL constraint only exist if the feature is set to a
pre-2026 value?
Definitely; the semantic will effectively be:
- protoc will resolve if the individual enum is resolved as scoped or
not (scoped = 2026 files or later, unless they affirmatively set the legacy
unscoped option for compatibility).
- If it is resolved as unscoped, protoc will try to check for value
name collisions between sibling enums, and generators are considered
'permitted' to emit the values unscoped.
- If it is resolved as scoped, protoc will not check for value
collisions, and generators will be required to always emit values scoped
(GoProto will just need to prefix the individual values with the
enum name
in all cases to guarantee the scoping).
On Tue, Jan 6, 2026 at 9:33 AM Max Kanat-Alexander <[email protected]>
wrote:
> Okay, good to know. That doesn't sound so bad in Go; it sounds *harder *to
> have a naming conflict, but still possible.
>
> So, I suppose the question is: does that IDL semantic need to persist in
> Edition 2026 if all protos are scoped? Like, should that IDL constraint
> only exist if the feature is set to a pre-2026 value?
>
> -Max
>
> On Tue, Jan 6, 2026 at 9:21 AM Em Rauch <[email protected]> wrote:
>
>> Go is the other big language that doesn't have scoped-enum concept in the
>> language, by virtue of not even having enum as a first class concept in the
>> language. GoProto prefixes values which would partially mitigate, but IIRC
>> it would also break at least in some cases today if we simply relaxed the
>> scoping restriction rule.
>>
>> Just FYI protoc will defensively prevent you from making enums which are
>> in the scope with enum values whose name collide in the same .proto file.
>> Formally we might say that "the values not being scoped to their containing
>> enum is the .proto IDL semantic, unrelated to any language",
>> pragmatically the main reason we don't relax it is to prevent you from
>> accidentally making a definition that would break in C++Proto. I think to
>> disable that check you would have to vendor and patch protoc to remove it,
>> and any downstream implications of that would obviously be on you at that
>> point.
>>
>> As long as you don't actually create such a value name collision in the
>> same .proto file protoc won't stop you though (it doesn't enforce the enum
>> value name prefixing or anything, that's just a style guide to try to avoid
>> collisions)
>>
>>
>>
>> On Mon, Jan 5, 2026 at 11:46 PM Max Kanat-Alexander <[email protected]>
>> wrote:
>>
>>> Okay, that makes sense. So basically, my enums won't change their format
>>> in code when they are scoped, but they will behave correctly in C++. Is C++
>>> the only language with the problem? I don't expect to need a C++ parser any
>>> time soon, so if that's the only place where it's a problem today, maybe I
>>> will just make top-level enums now and switch them to scoped when 2026
>>> comes out.
>>>
>>> -Max
>>>
>>> On Mon, Jan 5, 2026 at 10:04 AM Em Rauch <[email protected]> wrote:
>>>
>>>> So how would that look? Like say today I have:
>>>>> message Wrapper {
>>>>> enum Foo {
>>>>> UNSPECIFIED = 1;
>>>>> BAR = 1;
>>>>> }
>>>>> }
>>>>> Today I would be referring to that as Wrapper::Foo::BAR, IIRC (I
>>>>> haven't done C++ proto in a long time) or Wrapper.Foo.BAR in Python/Java
>>>>> (IIRC?). What does "enum Foo" at the top level look like instead?
>>>>
>>>>
>>>> Scoped enums would actually require no other behavior change in many of
>>>> the languages like Java, as the gencode actually uses a language enum which
>>>> is already scoped anyway. So in Java you're just going to get `Foo.BAR`
>>>> like you want without us having to do much special there.
>>>>
>>>> The C++ case is actually fairly odd today, basically what happens with
>>>> the wrapping type is that there's first an enum which manually prefixes
>>>> everything with the nested scope basically like this (the C++ enum semantic
>>>> is that all of the constants inside are not scoped by the containing enum)
>>>>
>>>> enum Wrapper_Foo : int {
>>>> Wrapper_Foo_UNSPECIFIED = 0;
>>>> Wrapper_Foo_BAR = 1;
>>>> }
>>>>
>>>> And then later the actual message class has `using` statements that
>>>> expose the type and names under that scape, like:
>>>>
>>>> class Wrapper {
>>>> using Foo = Wrapper_Foo;
>>>> static constexpr Foo UNSPECIFIED = Wrapper_Foo_UNSPECIFIED;
>>>> static constexpr Foo BAR = Wrapper_Foo_BAR;
>>>> }
>>>>
>>>> So today it is possible to write the enum type as either `Wrapper_Foo`
>>>> or `Wrapper::Foo`, and possible to name the values as either `Wrapper::BAR`
>>>> or `Wrapper_Foo_Bar`. You can see that this still would have the name
>>>> collisions if you had 2 enums nested in the same message and the value
>>>> names collided, since the values are also 'directly' underneath `Wrapper`
>>>> without any `Foo` in them there.
>>>>
>>>> C++ the language added scoped enums all the way back in C++11 (they
>>>> look like `enum class Foo {}`) so its far overdue for us to be able to have
>>>> the gencode use it there, then we can start to emit it as:
>>>>
>>>> enum class Foo : int {
>>>> UNSPECIFIED = 0;
>>>> BAR = 1;
>>>> }
>>>>
>>>> And you can finally write Foo::UNSPECIFIED like you naturally want to.
>>>>
>>>> All that to say, with scoped enums you will want to put them at top
>>>> level instead of synthetically-nested in a message and the 'spelling'
>>>> won't match. It's also a possibility that we could have some sort of shim
>>>> migration mode to facilitate people trying to incrementally move off the
>>>> nested-message-to-scope-pattern onto proper-scoped-enums but I'm not
>>>> exactly sure what it could look like to be a super smooth migration.
>>>>
>>>> On Mon, Jan 5, 2026 at 9:28 AM Max Kanat-Alexander <
>>>> [email protected]> wrote:
>>>>
>>>>> Ha, thanks Em! Wasn't sure anybody would recognize my name, still. :)
>>>>>
>>>>> Scoped by default sounds good. And I think that timeline would work
>>>>> for me, actually. And for what I'm working on, I can pick any edition I
>>>>> want; it's essentially green-field work where I get to define the format.
>>>>>
>>>>> So how would that look? Like say today I have:
>>>>>
>>>>> message Wrapper {
>>>>> enum Foo {
>>>>> UNSPECIFIED = 1;
>>>>> BAR = 1;
>>>>> }
>>>>> }
>>>>>
>>>>> Today I would be referring to that as Wrapper::Foo::BAR, IIRC (I
>>>>> haven't done C++ proto in a long time) or Wrapper.Foo.BAR in Python/Java
>>>>> (IIRC?). What does "enum Foo" at the top level look like instead?
>>>>>
>>>>> Basically I'm wondering: if I want to prepare for it now, can I name
>>>>> the empty messages in a particular way that will help me stay
>>>>> forward-compatible.
>>>>>
>>>>> Oh, and prototiller sounds cool. :)
>>>>>
>>>>> -Max
>>>>>
>>>>> On Mon, Jan 5, 2026 at 9:07 AM Em Rauch <[email protected]> wrote:
>>>>>
>>>>>> Always nice to recognize a xoogler name 🙂
>>>>>>
>>>>>> Broadly, the plan is for a future Edition number to have enums be
>>>>>> treated as scoped by default, but with a feature setting that opts back
>>>>>> in
>>>>>> to current behavior for people who want to upgrade the Edition number of
>>>>>> preexisting .proto files perfectly-behavior-preserving
>>>>>> (behavior-preserving
>>>>>> uprades should be tool assisted with a tool called Prototiller, whose OSS
>>>>>> implementation is unfortunately still not stabilized yet as we are
>>>>>> rewriting it to Go).
>>>>>>
>>>>>> Scoped enums is close to the top of the candidates list for Edition
>>>>>> 2026 which is targeted for 2026-Q3, but we don't have any firm
>>>>>> commitments
>>>>>> around Edition 2026 details at the moment.
>>>>>>
>>>>>> We don't intend to change the enum behavior on
>>>>>> proto2/proto3/Edition-2023/Edition-2024 files (or even support an option
>>>>>> there to do so), as our forward Editions strategy is to generally treat
>>>>>> the
>>>>>> behavior of older syntax IDL inputs as fixed as the way to avoid the
>>>>>> ecosystem problems that come from even adding new options that old
>>>>>> impls/infrastructure won't know about. So unfortunately anyone who plans
>>>>>> to
>>>>>> stay on Proto3 forever won't get the new goodness, you'll need to
>>>>>> continue
>>>>>> to just wrap each enum in an empty message if you want to avoid the
>>>>>> stupid
>>>>>> value name collision problems.
>>>>>>
>>>>>> > Is that actually on a roadmap anywhere? I don't see it in Issues.
>>>>>>
>>>>>> We mostly don't use Issues for tracking our roadmap work, primarily
>>>>>> Issues is for handling external bugs/requests/discussion (unlike gRPC
>>>>>> which
>>>>>> has community-driven CNCF governance, Protobuf is still a Google
>>>>>> project).
>>>>>> If you want to open it on Issues so you can be notified when it moves
>>>>>> forward, free to open and I'll tag the issue appropriately and we can try
>>>>>> to remember to keep it up to date.
>>>>>>
>>>>>> Thanks!
>>>>>>
>>>>>> On Mon, Jan 5, 2026 at 8:49 AM Max Kanat-Alexander <
>>>>>> [email protected]> wrote:
>>>>>>
>>>>>>> Hey proto team! :) The current docs say that scoped enums will be
>>>>>>> part of a future edition. Is that actually on a roadmap anywhere? I
>>>>>>> don't
>>>>>>> see it in Issues. I'm mostly just wondering if I should expect it by
>>>>>>> some
>>>>>>> vague date.
>>>>>>>
>>>>>>> I'm playing around with defining a configuration language based on a
>>>>>>> strict subset of textproto, and scoped enums would help a ton so that
>>>>>>> users
>>>>>>> could just write `state: ACTIVE` instead of the unintuitive `state:
>>>>>>> STATE_ACTIVE` in their config files. I know that I can accomplish that
>>>>>>> today by nesting enums inside of messages, but what I'm curious about
>>>>>>> is if
>>>>>>> the future potential implementation of scoped enums will break backwards
>>>>>>> compatibility with that in some way.
>>>>>>>
>>>>>>> -Max
>>>>>>>
>>>>>>> --
>>>>>>> You received this message because you are subscribed to the Google
>>>>>>> Groups "Protocol Buffers" group.
>>>>>>> To unsubscribe from this group and stop receiving emails from it,
>>>>>>> send an email to [email protected].
>>>>>>> To view this discussion visit
>>>>>>> https://groups.google.com/d/msgid/protobuf/25fac6eb-2e5f-43e3-bcd2-3ec3df783b56n%40googlegroups.com
>>>>>>> <https://groups.google.com/d/msgid/protobuf/25fac6eb-2e5f-43e3-bcd2-3ec3df783b56n%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>>>>> .
>>>>>>>
>>>>>>
--
You received this message because you are subscribed to the Google Groups
"Protocol Buffers" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/protobuf/CAKRmVH_g4PDRa8Ey4c1_1%3De91JT%3Db_%3Db-rxnrjYGgDJ4nD-Tnw%40mail.gmail.com.