Skip to content

Commit c199f07

Browse files
committed
Address immaterial changes
1 parent b8b3ac7 commit c199f07

File tree

1 file changed

+40
-34
lines changed

1 file changed

+40
-34
lines changed

text/3323-restrictions.md

Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ also a restriction, as it requires you to have a wildcard arm in a `match` expre
3535
are used on a daily basis by countless Rust programmers.
3636

3737
Restrictions are a powerful tool because the compiler stops you from doing something you are not
38-
allowed to do. If you violate a restriction by using trickery, such as transmuting a type, the
39-
resulting code is _unsound_.
38+
allowed to do. If you violate a restriction by using unsafe trickery, such as transmuting a type,
39+
the resulting code is _unsound_.
4040

4141
So why do we need restrictions? In fact, they are incredibly important. Those that have been around
4242
a while will remember a time before `#[non_exhaustive]`. Standard practice at that point in time was
@@ -155,8 +155,8 @@ pub struct Time {
155155

156156
The author of `time` would love to have these fields public. However, they do not want users to be
157157
able to change the values, as that would violate the invariants of the type. As a result they
158-
currently have to keep the fields private and write getters. What if, instead, they could add
159-
`mut(crate)` to a field, just like `pub(crate)`? This would allow them to write:
158+
currently have to keep the fields private and write "getter" methods. What if, instead, they could
159+
add `mut(crate)` to a field, just like `pub(crate)`? This would allow them to write:
160160

161161
```rust
162162
pub struct Time {
@@ -229,18 +229,19 @@ let x = Cell::new(5);
229229
x.set(6);
230230
```
231231

232-
Rust, as you may know, has [interior mutability]. This is what we are using here. `x` is not
233-
declared mutable, and it does not need to be. This is the beauty of interior mutability. But it
234-
introduces a key question: where is the mutation? The answer is that it is **not** a mutation for
235-
the purposes of this restriction. This is not because the value is not changed: it is. Rather, it is
236-
the logical result of the semantics of `mut` restrictions and where errors must occur (as described
237-
after the previous example). If errors are emitted at the point where the mutable reference is
238-
created, then there can be no such error here, as no mutable reference is ever created. `Cell::set`
239-
is a method that takes `&self`, not `&mut self`. Surely we can make interior mutability a special
240-
case, right? No; the only way to work around this is to make any reference to a type with interior
241-
mutability considered a mutation. Consequently, you could never have a reference to a type
242-
containing a `mut`-restricted, interior-mutable field. This is unacceptable, so interior mutability
243-
cannot be considered a mutation for the purposes of this restriction.
232+
Rust has [interior mutability], which is what we are using here. `x` is not declared mutable, and it
233+
does not need to be. This is the purpose of interior mutability, by definition. But it introduces a
234+
key question: where is the mutation? The answer is that it is **not** a mutation for the purposes of
235+
this restriction. This is not because the value is not changed: it is. Rather, it is the logical
236+
result of the semantics of `mut` restrictions and where errors must occur (as described after the
237+
previous example). If errors are emitted at the point where the mutable reference is created, then
238+
there can be no such error here, as no mutable reference is ever created. `Cell::set` is a method
239+
that takes `&self`, not `&mut self`. Interior mutability is not special-cased; the only way to work
240+
around this would be to make even non-mutable reference to a type with interior mutability
241+
considered a mutation. Consequently, you could never have a reference to a type containing a
242+
`mut`-restricted, interior-mutable field. This is unacceptable, so interior mutability cannot be
243+
considered a mutation for the purposes of this restriction. Interfaces that wish to restrict even
244+
_interior_ mutability of a field should avoid exposing it as a public field with private mutability.
244245

245246
[interior mutability]: https://doc.rust-lang.org/reference/interior-mutability.html
246247

@@ -262,8 +263,8 @@ Time {
262263
then the invariant would be violated, as there are only 24 hours in a day (numbered 0–23). Given
263264
that the invariant is not enforced by the type system, it cannot be enforced at all in this case. As
264265
a result, we have no choice but to disallow `struct` expressions for types with `mut`-restricted
265-
fields. This applies even when [functional update syntax][fru-syntax] is used, as invariants can
266-
rely on the value of other fields.
266+
fields, in scopes where any fields are `mut`-restricted. This applies even when
267+
[functional update syntax][fru-syntax] is used, as invariants can rely on the value of other fields.
267268

268269
[fru-syntax]: https://doc.rust-lang.org/stable/reference/expressions/struct-expr.html#functional-update-syntax
269270

@@ -292,19 +293,18 @@ to the current crate. However, there are other ways to restrict visibility. You
292293
`pub(super)` to restrict visibility to the parent module, and `pub(in path)` to restrict visibility
293294
to `path`, as long as that path is an ancestor of the location it is used. There is one additional
294295
case you have likely never encountered: `pub(self)`. The reason you have likely never seen this
295-
before is that it is completely useless. Why? `pub(self)` is identical to private, which is the
296-
default visibility.
297-
298-
While `pub(self)` should never be written in ordinary code, `impl(self)` and `mut(self)` are quite
299-
different. As the default restriction is unrestricted implementation and unrestricted mutation, it
300-
is more than likely that `impl(self)` and `mut(self)` will be quite common. During previous
301-
discussions about syntax, the unclear meaning of `impl(self)` and `mut(self)` was brought up. Syntax
302-
should have a clear meaning, and `impl(self)` and `mut(self)` are not clear. While they should be
303-
allowed for consistency with `pub(self)`, an alternative was needed with the same behavior.
304-
`impl(mod)` and `mut(mod)` should have a sufficiently clear meaning: implementing the trait and
305-
mutating the field are restricted to the current module. `impl(in mod)` and `mut(in mod)` are
306-
accepted as well. The behavior of `impl(mod)` is identical to `impl(self)`; likewise for `mut(mod)`
307-
and `mut(self)`.
296+
before is that it is redundant: `pub(self)` is identical to private, which is the default
297+
visibility.
298+
299+
While `pub(self)` should never be needed in most code, `impl(self)` and `mut(self)` are quite
300+
different. As no restrictions apply by default (anything visible can be implemented/mutated), is
301+
more than likely that `impl(self)` and `mut(self)` will be quite common. During previous discussions
302+
about syntax, the unclear meaning of `impl(self)` and `mut(self)` was brought up. Syntax should have
303+
a clear meaning, and `impl(self)` and `mut(self)` are not clear. While they should be allowed for
304+
consistency with `pub(self)`, an alternative was needed with the same behavior. `impl(mod)` and
305+
`mut(mod)` should have a sufficiently clear meaning: implementing the trait and mutating the field
306+
are restricted to the current module. `impl(in mod)` and `mut(in mod)` are accepted as well. The
307+
behavior of `impl(mod)` is identical to `impl(self)`; likewise for `mut(mod)` and `mut(self)`.
308308

309309
For consistency with the new restriction syntax, `pub(mod)` and `pub(in mod)` are also allowed.
310310

@@ -423,6 +423,7 @@ Trait aliases cannot be implemented. As such, there is no concern about compatib
423423
# Alternatives
424424

425425
- `impl` and `mut` restrictions could be attributes, similar to `#[non_exhaustive]`.
426+
- The proposed syntax could by syntactic sugar for these attributes.
426427

427428
# Prior art
428429

@@ -436,6 +437,8 @@ Trait aliases cannot be implemented. As such, there is no concern about compatib
436437
unhelpful to downstream users.
437438
- Various other languages have read-only fields, including C++, C#, Java, TypeScript, Kotlin, and
438439
Swift.
440+
- Users of many languages, including Rust, regularly implement read-only fields by providing a
441+
getter method without a setter method, demonstrating a need for this.
439442

440443
# Unresolved questions
441444

@@ -456,11 +459,14 @@ Trait aliases cannot be implemented. As such, there is no concern about compatib
456459

457460
# Future possibilities
458461

459-
- Sealed/exhaustive traits could happen in the future. This has the ability to impact coherence,
460-
such that other crates could rely on the fact that the list of implementations is exhaustive. As
461-
traits would default to unsealed, this does not have be decided now.
462+
- Explicitly sealed/exhaustive traits could happen in the future. This has the ability to impact
463+
coherence, such that other crates could rely on the fact that the list of implementations is
464+
exhaustive. As traits would default to unsealed, this does not have be decided now.
462465
- Trait items could gain proper visibility and/or restrictions of their own. This would allow
463466
private and/or defaulted trait items that cannot be overridden.
464467
- Set-once fields could potentially occur in the future. Functionally, this would be "true"
465468
read-only fields, in that they can be constructed but never mutated. They are not included in this
466469
proposal as the use case is nor clear, nor is there an immediately obvious syntax to support this.
470+
- The default could be changed in a future edition, such as to make `pub field: Type` be only
471+
mutable within the module rather than mutable everywhere. This seems unlikely, as it would be an
472+
incredibly disruptive change, and the benefits would have to be significant.

0 commit comments

Comments
 (0)