@@ -369,3 +369,61 @@ extend Foo {
369
369
370
370
Java generates the \" extension identifier\" ` bar ` , which is used to \" key\"
371
371
extension operations above.
372
+
373
+ ## Why Doesn't Protobuf Support Nullable Setters/Getters? {#nullable-setters-getters}
374
+
375
+ We have heard feedback that some folks would like protobuf to support nullable
376
+ getters/setters in their null-friendly language of choice (particularly Kotlin,
377
+ C#, and Rust). While this does seem to be a helpful feature for folks using
378
+ those languages, the design choice has tradeoffs which have led to the Protobuf
379
+ team choosing not to implement them.
380
+
381
+ The biggest reason not to have nullable fields is the intended behavior of
382
+ default values specified in a ` .proto ` file. By design, calling a getter on an
383
+ unset field will return the default value of that field.
384
+
385
+ As an example, consider this ` .proto ` file:
386
+
387
+ ``` proto
388
+ message Msg { optional Child child = 1; }
389
+ message Child { optional Grandchild grandchild = 1; }
390
+ message Grandchild { optional int32 foo = 1 [default = 72]; }
391
+ ```
392
+
393
+ and corresponding Kotlin getters:
394
+
395
+ ``` kotlin
396
+ // With our API where getters are always non-nullable:
397
+ msg.child.grandchild.foo == 72
398
+
399
+ // With nullable submessages the ?. operator fails to get the default value:
400
+ msg?.child?.grandchild?.foo == null
401
+
402
+ // Or verbosely duplicating the default value at the usage site:
403
+ (msg?.child?.grandchild?.foo ? : 72 )
404
+ ```
405
+
406
+ If a nullable getter existed, it would necessarily ignore the user-specified
407
+ defaults (to return null instead) which would lead to surprising and
408
+ inconsistent behavior. If users of nullable getters want to access the default
409
+ value of the field, they would have to write their own custom handling to use
410
+ the default if null is returned, which removes the supposed benefit of
411
+ cleaner/easier code with null getters.
412
+
413
+ Similarly, we do not provide nullable setters as the behavior would be
414
+ unintuitive. Performing a set and then get would not always give the same value
415
+ back, and calling a set would only sometimes affect the has-bit for the field.
416
+
417
+ Note that message-typed fields are always explicit presence fields (with
418
+ hazzers). Proto3 defaults to scalar fields having implicit presence (without
419
+ hazzers) unless they are explicitly marked ` optional ` , while Proto2 does not
420
+ support implicit presence. With
421
+ [ Editions] ( /editions/features#field_presence ) , explicit
422
+ presence is the default behavior unless an implicit presence feature is used.
423
+ With the forward expectation that almost all fields will have explicit presence,
424
+ the ergonomic concerns that come with nullable getters are expected to be more
425
+ of a concern than they may have been for Proto3 users.
426
+
427
+ Due to these issues, nullable setters/getters would radically change the way
428
+ default values can be used. While we understand the possible utility, we have
429
+ decided it’s not worth the inconsistencies and difficulty it introduces.
0 commit comments