Skip to content

Commit a23a5c9

Browse files
committed
Start writing the nameable_interfaces RFC
1 parent 1fea0c8 commit a23a5c9

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed

text/0000-nameable-interfaces.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
- Feature Name: nameable_interfaces
2+
- Start Date: 2016-2-10
3+
- RFC PR:
4+
- Rust Issue:
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
This RFC requires that an item which is nameable from a given module have an interface
10+
that is nameable from the module.
11+
12+
An item is "nameable" from a module if there is a path in the module's scope that resolves
13+
to the item, possibly through a reexport.
14+
By the "interface" of an item, I am referring to the "public-facing parts" of that item as defined
15+
in [RFC #0136](https://github.com/rust-lang/rfcs/pull/0136),
16+
i.e. the parts of the item that the RFC requires to be public whenever the item is public.
17+
18+
# Motivation
19+
[motivation]: #motivation
20+
21+
The primary motivation for nameable interfaces is refactorability.
22+
Nameable interfaces ensure that the type of any expression is nameable, guaranteeing that many
23+
common types of refactoring are always possible, including
24+
- type annotating a let declaration,
25+
- refactoring an expression without early returns into a function item,
26+
- refactoring a closure without upvars into a function item, and
27+
- refactoring a constant expression into a constant item.
28+
29+
Another motivation is documentability. This RFC would ensure that rustdoc never has to include
30+
an inaccessible path in the documentation for a crate.
31+
32+
# Detailed design
33+
[design]: #detailed-design
34+
35+
TODO describe design in more detail
36+
37+
Examples:
38+
```rust
39+
mod foo {
40+
mod bar {
41+
pub struct Bar;
42+
}
43+
44+
pub fn f() -> bar::Bar {}
45+
//~^ ERROR/WARN `f` is visible outside `foo`, but `bar::Bar` is not.
46+
//~| NOTE consider either not declaring `f` with `pub` or reexporting `bar::Bar`.
47+
}
48+
49+
mod foo {
50+
mod bar {
51+
pub struct Bar;
52+
}
53+
54+
mod baz {
55+
pub fn f() -> bar::Bar {}
56+
//~^ ERROR/WARN `f` is visible outside `foo`, but `bar::Bar` is not.
57+
}
58+
59+
pub use self::baz::f;
60+
//~^ NOTE consider either not reexporting `f` or also reexporing `bar::Bar`.
61+
}
62+
```
63+
64+
# Drawbacks
65+
[drawbacks]: #drawbacks
66+
67+
One drawback is the hassle for developers who have to fix unnameable interfaces or face warnings and
68+
eventually breakage (unless we keep it a warning indefinitely).
69+
One way to ameliorate this is to have clear warnings that suggest adding specific reexports
70+
that would bring the code up to compliance.
71+
72+
73+
The other main drawback is that adding the suggested reexports can sometimes expose previously
74+
private implementation details. More specifically,
75+
- reexporting a struct or an enum can allow access to its inherent methods,
76+
- reexporting a struct can allow access to its constructor and fields,
77+
- reexporting a trait allows access to its methods, and
78+
- reexporting an enum allows access to its variants and their fields.
79+
80+
[RFC #1422](https://github.com/rust-lang/rfcs/pull/1422) will address the first two points by
81+
allowing developers to rehide any exposed inherent methods, struct constructors, or struct fields.
82+
83+
More specifically, once can rehide inherent methods and struct fields by declaring them with the
84+
pub(restricted) syntax to restrict their visibility to where the corresponding struct or enum was
85+
nameable.
86+
For structs with fields, rehiding the fields will also rehide the constructor.
87+
For structs without fields, one must add a pub(restricted) dummy field to rehide the constructor.
88+
89+
To rehide enum variants and trait methods, RFC #1422 will have to be extended to allow the
90+
pub(restricted) syntax on trait methods, enum variants, and the variants' fields. I think this
91+
extension would be a good idea anyway.
92+
93+
# Alternatives
94+
[alternatives]: #alternatives
95+
96+
We could choose not to require that interfaces be nameable.
97+
98+
# Unresolved questions
99+
[unresolved]: #unresolved-questions
100+
101+
We could make nameable interfaces not only necessary but also sufficient to pass the
102+
`private_in_public` check in `librustc_privacy`. This would allow, for example,
103+
```rust
104+
mod foo {
105+
struct Bar; // `Bar` is nameable inside `foo`
106+
mod baz {
107+
pub fn f() -> Bar {} // Since f is not nameable outside `foo`, this use of `Bar` is ok.
108+
}
109+
}
110+
```
111+
112+
This addition would make nameability synonymous with visibility, which seems to be what most people
113+
expect (as evidenced by the discussions in rust issues
114+
[#18082](https://github.com/rust-lang/rust/issues/18082),
115+
[#23585](https://github.com/rust-lang/rust/issues/23585), and
116+
[#30905](https://github.com/rust-lang/rust/issues/30905)).

0 commit comments

Comments
 (0)