That sounds fantastic, thank you Em. :) -Max
On Tue, Jan 6, 2026 at 9:48 AM Em Rauch <[email protected]> wrote: > > 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/CACHWaZnViFb0sYG4mdjHQ_Z1T4qqC%3DxGM_OKbpz42StuKns2-g%40mail.gmail.com.
