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/CACHWaZnJc5BoPuM4cAOg8OchOOTC6s3P4dbJ71%2BiifqW00_qxQ%40mail.gmail.com.
