@@ -369,3 +369,61 @@ extend Foo {
369369
370370Java generates the \" extension identifier\" ` bar ` , which is used to \" key\"
371371extension 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