• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Minimum Required Edition
2
3**Author:** [@mcy](https://github.com/mcy)
4
5**Approved:** 2022-11-15
6
7A versioning mechanism for descriptors that ensures old runtimes do not load
8descriptors that are "too new."
9
10## Background
11
12Suppose we decide to add a novel definition like
13
14```
15const int32 MY_CONSTANT = 42;
16```
17
18to the Protobuf language. This would entail a descriptor change to track the
19values of constants, but they would not be loaded properly by older runtimes.
20This document describes an addition to `descriptor.proto` that prevents this
21version mismatch issue.
22
23[Protobuf Editions](what-are-protobuf-editions.md) intends to add the concept of
24an edition to Protobuf, which will be an approximately-annually incrementing
25value. Because of their annual nature, and because runtimes need to be updated
26to handle new features they implement regardless, we can use them as a poison
27pill for old runtimes that try to load descriptors that are "too new."
28
29## Overview
30
31We propose adding a new field to `FileDescriptorProto`:
32
33```
34optional string minimum_required_edition = ...;
35```
36
37This field would exist alongside the `edition` field, and would have the
38following semantics:
39
40Every Protobuf runtime implementation must specify the newest edition whose
41constructs it can handle (at a particular rev of that implementation). If that
42edition is less than `minimum_required_edition`, loading the descriptor must
43fail.
44
45"Less than" is defined per the edition total order given in
46[Life of an Edition](life-of-an-edition.md). To restate it, it is the following
47algorithm:
48
49```
50def edition_less_than(a, b):
51  parts_a = a.split(".")
52  parts_b = b.split(".")
53  for i in range(0, min(len(parts_a), len(parts_b))):
54    if int(parts_a[i]) < int(parts_b[i]): return True
55  return len(a) < len(b)
56```
57
58`protoc` should keep track of which constructions require which minimum edition.
59For example, if constants are introduced in edition 2025, but they are not
60present in a file, `protoc` should not require that runtimes understand
61constants by picking a lower edition, like 2023 (assuming no other construct
62requires a higher edition).
63
64In particular, the following changes should keep the minimum edition constant,
65with all other things unchanged:
66
67*   An upgrade of the proto compiler.
68*   Upgrading the specified edition of a file via Prototiller.
69
70### Bootstrapping Concerns
71
72"Epochs for `descriptor.proto`" (not available externally) describes a potential
73issue with bootstrapping. It is not the case here: minimum edition is only
74incremented once a particular file uses a new feature. Since `descriptor.proto`
75and other schemas used by `protoc` and the backends would not use new features
76immediately, introducing a new feature does not immediately stop the compiler
77from being able to compile itself.
78
79### Concerns for Schema Producers
80
81Schema producers should consider changes to their schemas that increase the
82minimum required edition to be breaking changes, since it will stop compiled
83descriptors from being loaded at runtime.
84
85## Recommendation
86
87We recommend adding the aforementioned minimum required edition field, along
88with the semantics it entails. This logic should be implemented entirely in the
89protoc frontend.
90
91## Alternatives
92
93### Use a Non-Editions Version Number
94
95Rather than using the editions value, use some other version number. This number
96would be incremented rarely (3-5 year horizon). This is the approach proposed
97in "Epochs for `descriptor.proto`."
98
99#### Pros
100
101*   Does not re-use the editions value for a semantically-different meaning; the
102    edition remains being "just" a key into a table of features defaults.
103
104#### Cons
105
106*   Introduces another version number to Protobuf that increments at its own
107    cadence.
108*   Could potentially be confused with the edition value, even though they serve
109    distinct purposes.
110
111### Minimum Required Edition Should Not Be Minimal
112
113The proto compiler should not guarantee that the minimum required edition is as
114small as it could possibly be.
115
116#### Pros
117
118*   Reduces implementation burden.
119
120#### Cons
121
122*   This introduces situations where an upgrade of the proto compiler, or an
123    innocuous change to a schema, can lead the the minimum required edition
124    being incremented. This is a problem for schema producers.
125
126### Do Nothing
127
128#### Pros
129
130*   Reduces churn in runtimes, since they do not need to implement new handling
131    for new *editions* (as contrasted to just *features)* regularly.
132*   Avoids a situation where old software cannot load new descriptors at
133    runtime.
134
135#### Cons
136
137*   Commits us to never changing the descriptor wire format in
138    backwards-incompatible ways, which has far-reaching effects on evolution.
139    These consequences are discussed in "Epochs for `descriptor.proto`."
140