RFC 0001: Private fields

lang (data-types | typesystem | privacy | product-types)

Summary

This is an RFC to make all struct fields private by default. This includes both tuple structs and structural structs.

Motivation

Reasons for default private visibility

Reasons for inherited visibility (today's design)

Detailed design

Currently, rustc has two policies for dealing with the privacy of struct fields:

This RFC is a proposal to unify the privacy of struct fields with the rest of the language by making them private by default. This means that both tuple variants and structural variants of structs would have private fields by default. For example, the program below is accepted today, but would be rejected with this RFC.

mod inner {
    pub struct Foo(u64);
    pub struct Bar { field: u64 }
}

fn main() {
    inner::Foo(10);
    inner::Bar { field: 10 };
}

Refinements to structural structs

Public fields are quite a useful feature of the language, so syntax is required to opt out of the private-by-default semantics. Structural structs already allow visibility qualifiers on fields, and the pub qualifier would make the field public instead of private.

Additionally, the priv visibility will no longer be allowed to modify struct fields. Similarly to how a priv fn is a compiler error, a priv field will become a compiler error.

Refinements on tuple structs

As with their structural cousins, it's useful to have tuple structs with public fields. This RFC will modify the tuple struct grammar to:

tuple_struct := 'struct' ident '(' fields ')' ';'
fields := field | field ',' fields
field := type | visibility type

For example, these definitions will be added to the language:

// a "newtype wrapper" struct with a private field
struct Foo(u64);

// a "newtype wrapper" struct with a public field
struct Bar(pub u64);

// a tuple struct with many fields, only the first and last of which are public
struct Baz(pub u64, u32, f32, pub int);

Public fields on tuple structs will maintain the semantics that they currently have today. The structs can be constructed, destructed, and participate in pattern matches.

Private fields on tuple structs will prevent the following behaviors:

These semantics are intended to closely mirror the behavior of private fields for structural structs.

Statistics gathered

A brief survey was performed over the entire mozilla/rust repository to gather these statistics. While not representative of all projects, this repository should give a good indication of what most structs look like in the real world. The repository has both libraries (libstd) as well as libraries which don't care much about privacy (librustc).

These numbers tally up all structs from all locations, and only take into account structural structs, not tuple structs.

Inherited privacyPrivate-by-default
Private fields14181852
Public fields20361602
All-private structs551 (52.23%)671 (63.60%)
All-public structs468 (44.36%)352 (33.36%)
Mixed privacy structs36 ( 3.41%)32 ( 3.03%)

The numbers clearly show that the predominant pattern is to have all-private structs, and that there are many public fields today which can be private (and perhaps should!). Additionally, there is on the order of 1418 instances of the word priv today, when in theory there should be around 1852. With this RFC, there would need to be 1602 instances of the word pub. A very large portion of structs requiring pub fields are FFI structs defined in the libc module.

Impact on enums

This RFC does not impact enum variants in any way. All enum variants will continue to inherit privacy from the outer enum type. This includes both the fields of tuple variants as well as fields of struct variants in enums.

Alternatives

The main alternative to this design is what is currently implemented today, where fields inherit the privacy of the outer structure. The pros and cons of this strategy are discussed above.

Unresolved questions

As the above statistics show, almost all structures are either all public or all private. This RFC provides an easy method to make struct fields all private, but it explicitly does not provide a method to make struct fields all public. The statistics show that pub will be written less often than priv is today, and it's always possible to add a method to specify a struct as all-public in the future in a backwards-compatible fashion.

That being said, it's an open question whether syntax for an "all public struct" is necessary at this time.