• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Edition Evolution
2
3**Author:** [@mcy](https://github.com/mcy)
4
5**Approved:** 2022-07-06
6
7## Overview
8
9[Protobuf Editions](what-are-protobuf-editions.md) give us a mechanism for
10pulling protobuf files into the future by upgrading their *edition*. Features
11are flags associated with syntax items of a `.proto` file; they can be either
12set explicitly, or they can be implied by the edition. Features can either
13correspond to behavior in `protoc`'s frontend (e.g. `proto:closed_enums`), or to
14a specific backend (`cpp:string_view`).
15
16This document seeks to answer:
17
18*   When do we create an edition?
19*   How do backends inform protoc of their defaults?
20
21## Proposal
22
23### Total Ordering of Editions
24
25**NOTE:** This topic is largely superseded by [Edition Naming](edition-naming.md).
26
27The `FileDescriptorProto.edition` field is a string, so that we can avoid nasty
28surprises around needing to mint multiple editions per year: even if we mint
29`edition = "2022";`, we can mint `edition = "2022b";` in a pinch.
30
31However, we might not own some third-party backends, and they might be unaware
32of when we decide to mint editions, and might want to mint editions on their
33own. Suppose that I maintain the Haskell protobuf backend, and I decide to add
34the `haskell:more_monads` feature. How do I get this into an edition?
35
36We propose defining a *total order* on editions. This means that a backend can
37pick the default not by looking at the edition, but by asking "is this proto
38older than this edition, where I introduced this default?"
39
40The total order is thus: the edition string is split on `'.'`. Each component is
41then ordered by `a.len < b.len && a < b`. This ensures that `9 < 10`,
42for example.
43
44By convention, we will make the edition be either the year, like `2022`, or the
45year followed by a revision, like `2022.1`. Thus, we have the following total
46ordering on editions:
47
48```
492022 < 2022.0 < 2022.1 < ... < 2022.9 < 2022.10 < ... < 2023 < ... < 2024 < ...
50```
51
52This means that backends (even though we don't particularly recommend it) can
53change defaults as often as they like. Thus, if I decide that
54`haskell:more_monads` becomes true in 2023, I simply ask
55`file.EditionIsLaterThan("2023")`. If it becomes false in 2023.1, a future
56backend can ask `file.EditionIsBetween("2023", "2023.1")`.
57
58### Creating an Edition
59
60In a sense, every edition already exists; it's just a matter of defining
61features on it.
62
63If the feature is a `proto:` feature, `protoc` intrinsically knows it, and it is
64implemented in the frontend.
65
66If the feature is a backend feature, the backend must be able to produce some
67kind of proto like `message Edition { repeated Feature defaults = 1; }` that
68describes what a specific edition must look like, based on less-than/is-between
69predicates like those above. That information can be used by protoc to display
70the full set of features it knows about given its backends. (The backend must,
71of course, use this information to make relevant codegen decisions.)
72
73### What about Editions "From the Future"?
74
75Suppose that in version v5.0 of my Haskell backend I introduced
76`haskell:more_monads`, and this has a runtime component to it; that is, the
77feature must be present in the descriptor to be able to handle parsing the
78message correctly.
79
80However, suppose I have an older service running v4.2. It is compiled with a
81proto that was already edition 2023 at build time (alternatively, it dynamically
82loads a proto). My v5.0 client sends it an incompatible message from "the
83future". Because a parse failure would be an unacceptable service degradation,
84we have a couple of options:
85
86*   Editions cannot introduce a feature that requires readers to accept new
87    encodings.
88    *   Similarly, editions cannot add restrictions that constrain past parsers.
89*   Editions may introduce such features, but they must somehow fit into some
90    kind of build horizon.
91
92The former is a reasonable-sounding but ultimately unacceptable position, since
93it means we cannot use editions if we wanted to, say, make it so that message
94fields are encoded as groups rather than length-prefixed chunks. The alternative
95is to define some kind of build horizon.