-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tracking Issue for Restrictions #105077
Comments
NB: My mostly-complete implementation uses |
Thanks for keeping the features separate! :) |
The whole this RFC is trying to solve is admittedly complicated in terms both of the concepts and the syntax but I found this RFC might relate to what I have proposed and provide with what I wanted: https://internals.rust-lang.org/t/structs-field-level-mutability-control-at-instantiation-not-at-definition/16061. The scoped mutability syntax included. |
This is not the place to rehash the RFC, expect for the listed unresolved questions. Also, saying you "found" the RFC is misleading — you are the one who created the thread. |
I would like to sketch a holistic mental model to shed some light on the unresolved questions: this, along with some other features like Under this model, the RFC splits up the existing visibility of fields into 1) the visibility of their value and address (read) and 2) the visibility of their construction and mutable place exprs (write). Similarly, it splits up the existing visibility of traits into 1) the visibility of the trait as a bound and 2) the visibility of its "construction" (impl-ability). (This comment on the RFC thread also notes that construction is fundamentally a whole-type property, not a per-field property.)
To me, this model implies answers to a few of the unresolved questions, and some future possibilities to consider:
However, having given my best shot above at making this proposal make sense to myself, I am concerned that the RFC was merged without sufficient motivation over existing practice. The cost of new syntax like this, especially when there are already idiomatic alternatives, weighs much more to me than having all these knobs available. Indeed, there were several well-reasoned comments in this direction, before and during the FCP (which I missed). For instance, the suggestion in rust-lang/rfcs#3323 (comment) and rust-lang/rfcs#3323 (comment) to reduce the feature's surface area based on more concrete examples. Attributes are already our main "escape valve" for new and increasingly niche syntax- this would address all the syntactic open questions even more effectively than the Or consider rust-lang/rfcs#3323 (comment) which makes a strong case that the |
I understand what you're saying with regard to a mental model, but I have to disagree with a fair amount.
The concern is not about enum variant fields. It is about having what is permitted as part of visibility being different in different places. For example, you couldn't do
I have no objection to full immutability. Without rereading the full RFC PR, I'm fairly certain I asked at least once for potential syntax, and no one provided anything that could be agreed upon. I would personally prefer For struct expressions, there is a key question that you did not address.
Unless there is a use case here, I see no reason to permit it. If you have a suggestion for a keyword other than
I believe that process-wise, this should require significant public discussion and possibly an FCP of some sort. Suggesting a mental model is one thing, but making decisions based off of it is another.
I addressed those links in the comments immediately following them.
If even one lang team member wanted it split, it would have been. I stated this repeatedly. If you have an issue with the RFC not being split, the time has passed. It was accepted as one, and as such both restrictions have been accepted (minus the unresolved questions). There is absolutely no reason to believe that the outcome would have been any different were the RFC split in two. Since you mention view types, however, the "handwaving" you're referring to (language that I find borderline rude) is identical to that of view types. They are complementary, and would have the same effect on splitting borrow checking. |
As a general note to anyone, I have a nearly complete implementation of restrictions on my fork of rustc. There is only one outstanding bug ( (in a separate comment because it's not in response to the prior comment) |
Mostly-complete implementation is up: #106074 Any assistance with figuring out the one bug is appreciated! |
Are restrictions proposed for the mutability of statics and extern statics? I didn't find this addressed one way or the other in the RFC text or RFC PR discussion. pub static mut(in …) ASDF: usize = 0;
extern "C" {
pub static mut(in …) JKL: usize;
} |
@dtolnay No one brought this up at any point. I think it's a reasonable enough extension that it shouldn't require another RFC. Once the current implementation PR is merged, I can look into it. |
Was something like a In any case I'm +1 for something like I kind of feel similarly for restricted fields. The RFC says
But to me, that sounds more like a reason to add some sort of "official" autoderevation for getters and setters, instead of adding complexity to how fields are defined. A benefit that these crates have is that the getters can be rewritten if their exact implementation needs to change, which is not possible with this proposal. Is introducing new, complicated syntax justified when it doesn't fully replicate the features of these crates? I'm not convinved it is. (Personally, I would continue to use edit: removed comment supporting the |
Regarding @dtolnay's suggestion - I've seen quite a bit that there's a general goal to migrate away from Currently I find alternatives to |
Nit: it's
Barring the addition of view types, getters and setters fundamentally cannot do the same thing that a public field can.
I disagree on the syntax being "complicated", but it absolutely replicates the features of the named crates and goes one step further in permitting partial borrows. Note that no one is forcing you to use
|
“Keyword soup” is exactly how this feels. |
@rben01 Do you have a concrete idea for the syntax? |
First, let me just say that I very much like the semantics of this RFC. It's just the syntax that I'm not a fan of. I think attributes would be more natural, and also more generalizable to similar cases of restriction not covered by this RFC, that there might be desire to cover in the the future. The concrete syntax I'd suggest would be something like this: pub mod foo {
pub mod bar {
#[restrict(impl(super))]
pub(crate) trait Foo {}
}
// can impl Foo here
}
// but not here
pub struct Time {
#[restrict(mut(crate))]
pub hour: u8,
#[restrict(mut(crate))]
pub minute: u8,
#[restrict(mut(crate))]
pub second: u8,
#[restrict(mut(crate))]
pub nanosecond: u32,
} This also has the advantage that it's clear a restriction is being added. The fact that In addition, attributes would open the door to “distributive” shorthands like #[restrict(mut(crate))] // applies to all fields in struct
pub struct Time {
pub hour: u8,
pub minute: u8,
pub second: u8,
pub nanosecond: u32,
}
pub enum Foo {
#[restrict(mut(crate))] // applies to all fields in variant
Alpha { x1: u8, x2: u8 },
Beta { y: u8 },
}
#[restrict(mut(crate))] // applies to all fields in all variants in enum
pub enum Bar {
Alpha { x1: u8, x2: u8 },
Beta { y: u8 },
} You could imagine, I suppose, In addition, having read the excellent analysis of all of the flavors of sealed-ness here, which explores more axes of restriction than just can- One example the article brings up is fn type_id(&self, _: private::Internal) -> TypeId where Self: 'static
#[restrict(override(crate), call(crate))]
fn type_id(&self) -> TypeId where Self: 'static There is no obvious keyword analog for this ( I understand that this is not the place to rehash the RFC — it's already been accepted — but, well, that's my concrete idea for a different syntax. |
I have no problem discussing it! My last comment was more of "ideas without proposals don't lead anywhere". It's worth noting that I originally proposed Overall I'm actually quite indifferent on syntax, and what you suggest is more than reasonable; it would solve a couple of the unresolved questions immediately as a result of being an attribute.
That is a very reasonable concern to have. Personally I wouldn't mind changing the default in an edition, but there would unquestionably be significant pushback as it's such a major change. For that reason I'm not actually proposing to do this.
This doesn't necessarily require attributes; the same could be done with native syntax.
Clearly you don't follow me on Mastodon 😉 I responded to the author in that restrictions covers one row of the table, while proper visibility on traits covers the remaining row. It is something that I want to do in the future, but I am viewing this as an extension of visibility, not restrictions.
The way I view it is this. Restrictions have been accepted, but the syntax has not, as it's explicitly listed as an unresolved question. Right now it's an idea that is being used in the initial implementation. Rehashing implies questioning the usefulness of restrictions as a whole, rather than trying to figure out details. I don't think it's that at all. |
Another syntax alternative is (ab)using where clauses. trait Foo<T>: Bar
where
impl in crate::mod_foo,
T: Copy
{
} This might especially make sense if the restriction has an impact on coherence |
The RFC was not split since the features require shared design work, but could trait restrictions and field restrictions be gated separately in implementation? They can keep a shared tracking issue for discussion since the syntax and some of the semantics must be cohesive. My thought is that assuming consensus on syntax is reached, it would be unfortunate to tie the stability of the items together if they turn out to require different amounts of design iteration. Of course they could also be split down the line, but easier to do it now than after implementation. Somewhat easier to review the initial impl too and narrow eventual bugs if the implementation isn't monolithic. |
The features are split! See the top issue and my first comment. The open PR does this already, and just needs me to update it. I do have thoughts of a different syntax that I believe will please everyone, but I'm holding off on saying what exactly that is until there's an implementation merged. |
please excuse if this has already been mentioned, but I have one thought on the field mutability restrictions: is there a downside to allowing struct initialisation and destructuring unless the non-exhaustive attribute is also set? |
That's pretty much it. In the RFC PR, I asked for situations where this would be the case and never received an answer (to my recollection). |
One thing that I don't immediately see how to do with the restrictions in this RFC, that I do see how to implement with Let me give an example:
Like I said, I really don't think it's necessary that the restrictions API cover all these weird possibilities... but it seemed like it might be worth mentioning |
The RFC as written doesn't permit this. However, once the initial implementation is merged (it's waiting on me) I intend to propose a syntax change to be attribute-based. That would resolve a lot of concerns and open the door to things not considered previously (like your example). |
This does for traits the analogous thing I would like to see similar syntax for
The |
Mutability restriction is closely related to recent @nikomatsakis's blog post https://smallcultfollowing.com/babysteps/blog/2024/09/26/overwrite-trait/ . In that post Niko proposes to restrict field mutability and also to restrict value overwriting (i. e. |
@safinaskar Right now restrictions (including mut restrictions) have been accepted by an RFC, while the overwrite trait is a blog post. If Niko would like to propose it formally, he is of course free to do so. Until then I'm not sure what the relevance is here. |
Thanks @safinaskar for raising the question. I've been wondering about the interaction. In some sense it's not deep-- the Overwrite trait (which I tend to refer to as Replace these days, I need to write some follow ups...) would be a way to make enforceable immutable fields ("truly immutable"). It makes this proposal more meaningful since things that are private (or privately mutable) could not be changed by replacing the struct wholesale. The other interaction I see is more syntactic and is mostly orthogonal: if you declare a struct field as mut (or mut(crate), etc), does that mean the other fields are NOT mut? Re: this RFC, it's true there's an accepted RFC but it's also true that when things lay dormant for 2 years they lose some "sticking power". And even when the RFC was accepted the syntax was largely unsettled. I have some definite mixed feelings about the syntax in the RFC and would expect to consider potential interaction with ideas that have arisen since. That said, as I wrote, I don't see any major conflict between the two. The main thing is that it suggests there could be value to having the idea of non-assignable fields, which i think is true even without the Overwrite trait (though significantly less). |
This is a tracking issue for the RFC "Restrictions" (rust-lang/rfcs#3323).
The feature gates for the issue are:
#![feature(impl_restriction)]
#![feature(mut_restriction)]
About tracking issues
Tracking issues are used to record the overall progress of implementation.
They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions.
A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature.
Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.
Steps
Unresolved Questions
sealed
orreadonly
. Adifferent syntax altogether could be used as well.
strict or less strict than the visibility. This warning could also be used for
pub(self)
.macro_rules!
matchers? There is currently avis
matcher, butit is likely unwise to add a new matcher for each restriction.
vis
matcher, as it does not current restrict thetokens that can follow. For this reason, it could break existing code, such as the following
example.
restriction
matcher could work, but restrictions are not the same everywhere.mut_restriction
andimpl_restriction
are relatively long.can be added in the future indicating when an item had its restriction lifted, if applicable.
The design for this is left to the language team as necessary. A decision does not need to be
made prior to stabilization, as stability attributes are not stable in their own right.
in
syntax be permitted for restrictions? Including it is consistent with the existingsyntax for visibility. Further, the lack of inclusion would lead to continued use of the
workaround for
impl
. Formut
, there is no workaround. The syntax is not used often forvisibility, but it is very useful when it is used.
struct
expressions be disallowed?construction with unchecked values?
Implementation history
The text was updated successfully, but these errors were encountered: