Skip to content

Commit 98565f7

Browse files
committed
RFC: Private fields by default
1 parent ae658ea commit 98565f7

File tree

1 file changed

+161
-0
lines changed

1 file changed

+161
-0
lines changed

active/0000-private-fields.md

+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
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

Comments
 (0)