|
| 1 | +# Summary |
| 2 | + |
| 3 | +This is an RFC to make all struct fields private by default. This includes both |
| 4 | +tuple structs and structural structs. |
| 5 | + |
| 6 | +# Motivation |
| 7 | + |
| 8 | +Reasons for default private visibility |
| 9 | + |
| 10 | +* Visibility is often how soundness is achieved for many types in rust. These |
| 11 | + types are normally wrapping unsafe behavior of an FFI type or some other |
| 12 | + rust-specific behavior under the hood (such as the standard `Vec` type). |
| 13 | + Requiring these types to opt-in to being sound is unfortunate. |
| 14 | + |
| 15 | +* Forcing tuple struct fields to have non-overridable public visibility greatly |
| 16 | + reduces the utility of such types. Tuple structs cannot be used to create |
| 17 | + abstraction barriers as they can always be easily destructed. |
| 18 | + |
| 19 | +* Private-by-default is more consistent with the rest of the Rust language. All |
| 20 | + other aspects of privacy are private-by-default except for enum variants. Enum |
| 21 | + variants, however, are a special case in that they are inserted into the |
| 22 | + parent namespace, and hence naturally inherit privacy. |
| 23 | + |
| 24 | +* Public fields of a `struct` must be considered as part of the API of the type. |
| 25 | + This means that the exact definition of all structs is *by default* the API of |
| 26 | + the type. Structs must opt-out of this behavior if the `priv` keyword is |
| 27 | + required. By requiring the `pub` keyword, structs must opt-in to exposing more |
| 28 | + surface area to their API. |
| 29 | + |
| 30 | +Reasons for inherited visibility (today's design) |
| 31 | + |
| 32 | +* Public definitions like `pub struct Point { x: int, y: int }` are concise and |
| 33 | + easy to read. |
| 34 | +* Private definitions certainly want private fields (to hide implementation |
| 35 | + details). |
| 36 | + |
| 37 | +# Detailed design |
| 38 | + |
| 39 | +Currently, rustc has two policies for dealing with the privacy of struct fields: |
| 40 | + |
| 41 | +* Tuple structs have public fields by default (including "newtype structs") |
| 42 | +* Fields of structural structs (`struct Foo { ... }`) inherit the same privacy |
| 43 | + of the enclosing struct. |
| 44 | + |
| 45 | +This RFC is a proposal to unify the privacy of struct fields with the rest of |
| 46 | +the language by making them private by default. This means that both tuple |
| 47 | +variants and structural variants of structs would have private fields by |
| 48 | +default. For example, the program below is accepted today, but would be rejected |
| 49 | +with this RFC. |
| 50 | + |
| 51 | +```rust |
| 52 | +mod inner { |
| 53 | + pub struct Foo(u64); |
| 54 | + pub struct Bar { field: u64 } |
| 55 | +} |
| 56 | + |
| 57 | +fn main() { |
| 58 | + inner::Foo(10); |
| 59 | + inner::Bar { field: 10 }; |
| 60 | +} |
| 61 | +``` |
| 62 | + |
| 63 | +### Refinements to structural structs |
| 64 | + |
| 65 | +Public fields are quite a useful feature of the language, so syntax is required |
| 66 | +to opt out of the private-by-default semantics. Structural structs already allow |
| 67 | +visibility qualifiers on fields, and the `pub` qualifier would make the field |
| 68 | +public instead of private. |
| 69 | + |
| 70 | +Additionally, the `priv` visibility will no longer be allowed to modify struct |
| 71 | +fields. Similarly to how a `priv fn` is a compiler error, a `priv` field will |
| 72 | +become a compiler error. |
| 73 | + |
| 74 | +### Refinements on tuple structs |
| 75 | + |
| 76 | +As with their structural cousins, it's useful to have tuple structs with public |
| 77 | +fields. This RFC will modify the tuple struct grammar to: |
| 78 | + |
| 79 | +```ebnf |
| 80 | +tuple_struct := 'struct' ident '(' fields ')' ';' |
| 81 | +fields := field | field ',' fields |
| 82 | +field := type | visibility type |
| 83 | +``` |
| 84 | + |
| 85 | +For example, these definitions will be added to the language: |
| 86 | + |
| 87 | +```rust |
| 88 | +// a "newtype wrapper" struct with a private field |
| 89 | +struct Foo(u64); |
| 90 | + |
| 91 | +// a "newtype wrapper" struct with a public field |
| 92 | +struct Bar(pub u64); |
| 93 | + |
| 94 | +// a tuple struct with many fields, only the first and last of which are public |
| 95 | +struct Baz(pub u64, u32, f32, pub int); |
| 96 | +``` |
| 97 | + |
| 98 | +Public fields on tuple structs will maintain the semantics that they currently |
| 99 | +have today. The structs can be constructed, destructed, and participate in |
| 100 | +pattern matches. |
| 101 | + |
| 102 | +Private fields on tuple structs will prevent the following behaviors: |
| 103 | + |
| 104 | +* Private fields cannot be bound in patterns (both in irrefutable and refutable |
| 105 | + contexts, i.e. `let` and `match` statements). |
| 106 | +* Private fields cannot be specified outside of the defining module when |
| 107 | + constructing a tuple struct. |
| 108 | + |
| 109 | +These semantics are intended to closely mirror the behavior of private fields |
| 110 | +for structural structs. |
| 111 | + |
| 112 | +### Statistics gathered |
| 113 | + |
| 114 | +A brief survey was performed over the entire `mozilla/rust` repository to gather |
| 115 | +these statistics. While not representative of all projects, this repository |
| 116 | +should give a good indication of what most structs look like in the real world. |
| 117 | +The repository has both libraries (`libstd`) as well as libraries which don't |
| 118 | +care much about privacy (`librustc`). |
| 119 | + |
| 120 | +These numbers tally up all structs from all locations, and only take into |
| 121 | +account structural structs, not tuple structs. |
| 122 | + |
| 123 | +| | Inherited privacy | Private-by-default | |
| 124 | +|-----------------------|------------------:|-------------------:| |
| 125 | +| Private fields | 1418 | 1852 | |
| 126 | +| Public fields | 2036 | 1602 | |
| 127 | +| All-private structs | 551 (52.23%) | 671 (63.60%) | |
| 128 | +| All-public structs | 468 (44.36%) | 352 (33.36%) | |
| 129 | +| Mixed privacy structs | 36 ( 3.41%) | 32 ( 3.03%) | |
| 130 | + |
| 131 | +The numbers clearly show that the predominant pattern is to have all-private |
| 132 | +structs, and that there are many public fields today which can be private (and |
| 133 | +perhaps should!). Additionally, there is on the order of 1418 instances of the |
| 134 | +word `priv` today, when in theory there should be around `1852`. With this RFC, |
| 135 | +there would need to be `1602` instances of the word `pub`. A very large portion |
| 136 | +of structs requiring `pub` fields are FFI structs defined in the `libc` |
| 137 | +module. |
| 138 | + |
| 139 | +### Impact on enums |
| 140 | + |
| 141 | +This RFC does not impact enum variants in any way. All enum variants will |
| 142 | +continue to inherit privacy from the outer enum type. This includes both the |
| 143 | +fields of tuple variants as well as fields of struct variants in enums. |
| 144 | + |
| 145 | +# Alternatives |
| 146 | + |
| 147 | +The main alternative to this design is what is currently implemented today, |
| 148 | +where fields inherit the privacy of the outer structure. The pros and cons of |
| 149 | +this strategy are discussed above. |
| 150 | + |
| 151 | +# Unresolved questions |
| 152 | + |
| 153 | +As the above statistics show, almost all structures are either all public or all |
| 154 | +private. This RFC provides an easy method to make struct fields all private, but |
| 155 | +it explicitly does not provide a method to make struct fields all public. The |
| 156 | +statistics show that `pub` will be written less often than `priv` is today, and |
| 157 | +it's always possible to add a method to specify a struct as all-public in the |
| 158 | +future in a backwards-compatible fashion. |
| 159 | + |
| 160 | +That being said, it's an open question whether syntax for an "all public struct" |
| 161 | +is necessary at this time. |
0 commit comments