File: protobuf-design-options-attributes.md

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (247 lines) | stat: -rw-r--r-- 7,383 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# Protobuf Design: Options Attributes

A proposal to create target and retention attributes to support.

**Author:** [@kfm](https://github.com/fowles)

**Approved:** 2022-08-26

## Background

The [Protobuf Editions](what-are-protobuf-editions.md) project plans to use
[custom options](protobuf-editions-design-features.md) to model features and
encourage language bindings to build custom features off options as well.

This design proposed the specific addition of `target` and `retention`
attributes for options as well as their suggested meaning.

Both `target` and `retention` attributes are no-ops when applied to fields that
are not options (either from descriptor.proto or custom options).

## Target Attributes

Historically, options have only applied to specific entities, but features will
be available on most entities. To allow language specific extensions to restrict
the places where options can bind, we will allow features to explicitly specify
the targets they apply to (similar in concept to the "target" attribute on Java
annotations). `TARGET_TYPE_UNKNOWN` will be treated as absent.

```
message FieldOptions {
  ...
  optional OptionTargetType target = 17;

  enum OptionTargetType {
    TARGET_TYPE_UNKNOWN = 0;
    TARGET_TYPE_FILE = 1;
    TARGET_TYPE_EXTENSION_RANGE = 2;
    TARGET_TYPE_MESSAGE = 3;
    TARGET_TYPE_FIELD = 4;
    TARGET_TYPE_ONEOF = 5;
    TARGET_TYPE_ENUM = 6;
    TARGET_TYPE_ENUM_VALUE = 7;
    TARGET_TYPE_SERVICE = 8;
    TARGET_TYPE_METHOD = 9;
  };
}
```

If no target is provided, `protoc` will permit the target to apply to any
entity. Otherwise, `protoc` will allow an option to be applied at either the
file level or to its target entity (and will produce a compile error for any
other placement). For example

```
message Features {
  ...

  enum EnumType {
    OPEN = 0;
    CLOSED = 1;
  }
  optional EnumType enum = 2 [
      target = TARGET_TYPE_ENUM
  ];
}
```

would allow usage of

```
// foo.proto
edition = "tbd"

option features.enum = OPEN;  // allowed at FILE scope

enum Foo {
  option features.enum = CLOSED;  // allowed at ENUM scope
  A = 2;
  B = 4;
}

message Bar {
  option features.enum = CLOSED;  // disallowed at Message scope

  enum Baz {
    C = 8;
  }
}
```

## Retention

To reduce the size of descriptors in protobuf runtimes, features will be
permitted to specify retention rules (again similar in concept to "retention"
attributes on Java annotations).

```
enum FeatureRetention {
  RETENTION_UNKNOWN = 0;
  RETENTION_RUNTIME = 1;
  RETENTION_SOURCE = 2;
}
```

Options intended to inform code generators or `protoc` itself can be annotated
with `SOURCE` retention. The default retention will be `RUNTIME` as that is the
current behavior for all options. **Code generators that emit generated
descriptors will be required to omit/strip options with `SOURCE` retention from
their generated descriptors.** For example:

```
message Cpp {
  enum StringType {
    STRING = 1;
    STRING_VIEW = 0;
    CORD = 2;
  }

  optional string namespace = 2 [
      retention = RETENTION_SOURCE,
      target = TARGET_TYPE_FILE
  ];
}
```

## Motivation

While the proximal motivation for these options is for use with "features" in
"editions", I believe they provide sufficient general utility that adding them
directly to `FieldDescriptorOptions` is warranted. For example, significant
savings in binary sizes could be realized if `ExtensionRangeOptions::Metadata`
had only `SOURCE` retention. Previously, we have specifically special-cased this
behavior on a per-field basis, which does work but does not provide good
extensibility.

## Discussion

In the initial design `target` was serving the dual purpose of identifying the
semantic entity, and also the granularity of inheritance for features. After
discussion about concerns around over use of inheritance, we decided for a
slightly refined definition that decouples these concerns. `target` **only**
specifies the semantic entity to which an option can apply. Features will be
able to be set on both the `FILE` level and their semantic entity. Everything in
between will be refused in the initial release. This allows us a clean
forward-compatible way to allow arbitrary feature inheritance, but doesn't
commit us to doing that until we need it.

Similarly, we will start with `optional` target, because we can safely move to
`repeated` later should the need arise.

The naming for `target` and `retention` are directly modeled after Java
annotations. Other names were considered, but no better name was found and the
similarity to an existing thing won the day.

## Alternatives

### Use a repeated `target` proposed

This is the proposed alternative.

#### Pros

*   Allows fine-grained control of target applicability.

#### Cons

*   Harder to generalize for users (every feature's specification is potentially
    unique).

### Allow hierarchy based on `target` semantic location.

Rather than having a repeated `target` that specifies all locations, we allow
only the level at which it semantically applies to be specified. The protoc
compiler will implicitly allow the field to be used on entities that can
lexically group that type of entry. For this `target` can be either singular or
repeated.

#### Pros

*   Enables tooling that understands when a feature is used for grouping vs when
    it has semantic value (helpful for minimizing churn in large-scale changes).
*   Easier to generalize for users (any `FIELD` feature can apply to a message
    as opposed to only the `FIELD` features that explicitly specified an
    additional `target`).

#### Cons

*   Forces all `target` applications to be permitted on scoping entities.

### Use Custom Options (aka "We Must Go Deeper")

Rather than building `retention` and `target` directly as fields of
`FieldOptions`, we could use custom options to define an equivalent thing. This
option was rejected because it pushes extra syntax onto users for a fundamental
feature.

#### Pros

*   Doesn't require modifying `descriptor.proto`.

#### Cons

*   Requires a less-intuitive spelling in user code.
*   Requires an additional import for users.
*   Language-level features would have to have a magic syntax or a side table
    instead of using the same consistent option as user per code gen features.

### Hard Code Behaviors in `protoc`

Rather than building a generic mechanism we could simply hard code the behavior
of protoc and document it.

#### Pros

*   Can't be misused.

#### Cons

*   Not extensible for users.
*   Requires more special cases users need to learn.

### Original Approved Proposal

The proposal as originally approved had some slight differences from what was
ultimately implemented:

*   The retention enum did not have an `UNKNOWN` type.
*   The enums were defined at the top level instead of nested inside
    `FieldOptions`.
*   The enum values did not have a scoping prefix.
*   The target enum had a `STREAM` entry, but this turned out to be unnecessary
    since the syntax that it applied to was removed.

### Do Nothing

We could omit this entirely and get ice cream instead. This was rejected because
the proliferation of features on entities they do not apply to is considered too
high a cost.

#### Pros

*   Ice cream is awesome.

#### Cons

*   Doesn't address any of the problems that caused this to come up.
*   Some people are lactose intolerant.