# Edition Evolution **Author:** [@mcy](https://github.com/mcy) **Approved:** 2022-07-06 ## Overview [Protobuf Editions](what-are-protobuf-editions.md) give us a mechanism for pulling protobuf files into the future by upgrading their *edition*. Features are flags associated with syntax items of a `.proto` file; they can be either set explicitly, or they can be implied by the edition. Features can either correspond to behavior in `protoc`'s frontend (e.g. `proto:closed_enums`), or to a specific backend (`cpp:string_view`). This document seeks to answer: * When do we create an edition? * How do backends inform protoc of their defaults? ## Proposal ### Total Ordering of Editions **NOTE:** This topic is largely superseded by [Edition Naming](edition-naming.md). The `FileDescriptorProto.edition` field is a string, so that we can avoid nasty surprises around needing to mint multiple editions per year: even if we mint `edition = "2022";`, we can mint `edition = "2022b";` in a pinch. However, we might not own some third-party backends, and they might be unaware of when we decide to mint editions, and might want to mint editions on their own. Suppose that I maintain the Haskell protobuf backend, and I decide to add the `haskell:more_monads` feature. How do I get this into an edition? We propose defining a *total order* on editions. This means that a backend can pick the default not by looking at the edition, but by asking "is this proto older than this edition, where I introduced this default?" The total order is thus: the edition string is split on `'.'`. Each component is then ordered by `a.len < b.len && a < b`. This ensures that `9 < 10`, for example. By convention, we will make the edition be either the year, like `2022`, or the year followed by a revision, like `2022.1`. Thus, we have the following total ordering on editions: ``` 2022 < 2022.0 < 2022.1 < ... < 2022.9 < 2022.10 < ... < 2023 < ... < 2024 < ... ``` This means that backends (even though we don't particularly recommend it) can change defaults as often as they like. Thus, if I decide that `haskell:more_monads` becomes true in 2023, I simply ask `file.EditionIsLaterThan("2023")`. If it becomes false in 2023.1, a future backend can ask `file.EditionIsBetween("2023", "2023.1")`. ### Creating an Edition In a sense, every edition already exists; it's just a matter of defining features on it. If the feature is a `proto:` feature, `protoc` intrinsically knows it, and it is implemented in the frontend. If the feature is a backend feature, the backend must be able to produce some kind of proto like `message Edition { repeated Feature defaults = 1; }` that describes what a specific edition must look like, based on less-than/is-between predicates like those above. That information can be used by protoc to display the full set of features it knows about given its backends. (The backend must, of course, use this information to make relevant codegen decisions.) ### What about Editions "From the Future"? Suppose that in version v5.0 of my Haskell backend I introduced `haskell:more_monads`, and this has a runtime component to it; that is, the feature must be present in the descriptor to be able to handle parsing the message correctly. However, suppose I have an older service running v4.2. It is compiled with a proto that was already edition 2023 at build time (alternatively, it dynamically loads a proto). My v5.0 client sends it an incompatible message from "the future". Because a parse failure would be an unacceptable service degradation, we have a couple of options: * Editions cannot introduce a feature that requires readers to accept new encodings. * Similarly, editions cannot add restrictions that constrain past parsers. * Editions may introduce such features, but they must somehow fit into some kind of build horizon. The former is a reasonable-sounding but ultimately unacceptable position, since it means we cannot use editions if we wanted to, say, make it so that message fields are encoded as groups rather than length-prefixed chunks. The alternative is to define some kind of build horizon.