-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Trait method impl restrictions #3678
base: master
Are you sure you want to change the base?
Conversation
We've past proposals for inherent trait methods I think, mostly proposing a second inherent looking There is however a question of default speed vs size optimizations in vtables, aka do these methods appear in the vtable, or do they have a generic implementation for every type? Also, how does one flag that these method should appear in a vtable, or should use a generic implementation for every type? |
It might be better to have this as an attribute rather than yet another potential keyword position for parsing to deal with. Otherwise, great. |
@Lokathor wrote:
I get that, but on the flip side, that'd be inconsistent with RFC 3323, and it seems awkward to use a keyword in one place and an attribute in another. |
@burdges wrote:
That might be equivalent to a subset of this, depending on the details. I haven't seen those proposals.
In theory, if you have a method that can't be overridden outside of the crate/module, and nothing overrides it, you could optimize by omitting it from the vtable. I don't think that optimization should be mandatory, or required for initial implementation, though. |
I'm more asking what's the best default. If the best default were to be in the vtable, then you can just do
I'd expect If otoh the best default were not to be in the vtable, then rustc should do something more complex. Anyways yeah maybe not relevant here. |
Another future possibility could be to add |
@bluebear94 Interesting! So, rather than requiring |
this would be quite useful for stabilizing |
@programmerjake That's a great use case, thank you! |
This seems like a reasonable and desirable extension to RFC 3323. So I propose... @rfcbot fcp merge Thanks @joshtriplett for writing this up. I note that syntax was left as an open item on RFC 3323, and so we're implicitly carrying that open item here also. |
Team member @traviscross has proposed to merge this. The next step is review by the rest of the tagged team members: Concerns:
Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns. |
Big +1 to having something like this. @rfcbot concern visiblity-style-vs-final-style I think these are far more than a syntax difference, so I want to talk about it more. As a couple of examples:
So is the visibility phrasing here actually important? Do we actually need it? The cases I know of don't need it
The provided implementation of a Thus my inclination is that we should do the |
I think |
If it is to be an attribute then I would prefer something like I assume the syntax was chosen for parity with RFC3323, but I think it is okay to deviate from this if it comes with a simplification. |
Note that the RFC allows for
This is something I specifically checked to ensure was there before proposing FCP merge, in part for the reasons you mention. |
This comment was marked as duplicate.
This comment was marked as duplicate.
I think that that just pushes me even more to skip the If we need a special syntax, let's make it (And, aesthetically, |
Avoid implying that this should always happen if possible. The compiler may not always want to do this.
(Aside, TC: it'd be nice to have your concerns in the thread here, rather than in an external document.) When I look at
I prefer to think about the intent someone has, rather than any particular language details. (Niko's https://internals.rust-lang.org/t/bikeshed-rename-catch-blocks-to-fallible-blocks/7121/4?u=scottmcm post really changed how I think about a bunch of these things, where it's not quite the same as something else but it's close enough that reusing existing intuition is valuable.) If I'm using a Whether that's (Whether that's |
This is where I point out what we're going to decide in... ...which is that this program will work and print "cat": trait Mammal {
//#[final] // <--- Write this to prevent the "override" below?
fn frob(&self) { println!("mammal") }
}
trait Cat: Mammal { // "Cat extends Mammal..."
fn frob(&self) { println!("cat") }
}
fn f(x: impl Cat) {
x.frob() // Prints "cat".
} That is, there already is this way of "extending" traits with subtraits, and there will soon be this other axis for the "overriding" of a method. This other axis is a better fit for And given that we already support the conceptually similar: trait Tr {}
impl dyn Tr + '_ {
// This is an inherent method on
// `dyn` instances of the trait.
fn f(&self) {}
}
fn g(x: &dyn Tr) {
x.f();
} ...what we're talking about in this RFC seems to me much more like "inherent" methods than "final" ones, whatever syntax we choose for that. To your point about considering intent, my intent here would be to add an inherent method, carrying over my intuitions about what that means elsewhere in Rust, such as in the above. That is, I don't think we need to import a concept here. We already have one! @joshtriplett and I talked this through last week, and on the basis of these considerations, he's planning to update this RFC to change With that, I'll be happy to check the box here (or propose FCP merge myself), and we can dig into further discussion on the open item when time permits. |
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
…locks Add an unresolved question to consider whether we want one or both of these.
@traviscross I've updated the RFC, and I think you can now resolve your concern |
I think the word "inherent" is defined in the Reference to mean methods that are defined in an types's own The result is that the word "inherent" has come to mean "a method defined on the type itself, not on some trait that it implements". Therefore this is the wrong term to use for this feature. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
This has an analogous meaning: "method defined by the trait itself, not by any instance of the trait". |
Yes, I can see the analogy. However, this is very confusing, and a different term would be much better. This breaks a whole lot of existing documentation (both within the rust-lang org, and elsewhere, and presumably error messages) that talks about "inherent methods". |
To expand on that: it's all very well to have some analogy that justifies the usage, but what really matters is qutestions like:
|
Coming here from TWIR, I also like |
I thought we were going to restart proposed FCP. I'm not that happy with @rfcbot concern proposed FCP should be restarted with a new name Looking over the comments, I think there are two "attractor states" I'm comfortable with:
Given the open questions on the second I would just go with the first for now. Extending the meaning of "inherent" from "inherent to a type" to "inherent to a trait" is something one can logically do, but it isn't clear to me what we gain from that. "Inherent" is already a term not that many users know, since there's no syntax for it, and the existing intuition they do have will have to be modified to make this term work. In the meantime there will be user confusion and we will have to spend a lot of time explaining what it means. That doesn't seem worth it to me when we have a word that users will already intuitively understand.
I really don't agree. Shadowing a method name is not analogous to overriding a method. They are completely different methods, and shadowing does not prevent access to the original method. The intent of the feature in #3624 is to allow supertraits to add method names that are already defined by subtraits. If the goal is to prevent this mechanism from being abused I wouldn't want a world where best practice is to declare every method in a new trait as |
Let's do that cancel first. Then we can write up something to restart. @rfcbot fcp cancel |
@traviscross proposal cancelled. |
😮💨 can the keyword bikeshedding be deferred until before stabilization? |
Procedurally I raised an objection because the keyword is not listed as an open question; as the RFC is written we are committing to it today, but most lang members checked their box when it was a different keyword. Procedurally the bikeshed could be deferred, as in the keyword could be moved to an open question, but practically I don't see what we would gain from that. The feature has straightforward semantics and the debate is not likely to be resolved through experience using it. The choice of how to expose this feature depends on taking differing mental models and building a coherent vision for the language. That's the stuff of RFCs. |
@tmandry 👍 for restarting the FCP, as you've done. And FWIW, I personally agree and prefer |
I'll write something more up here, but as a placeholder for now... For me, the similarity between the user-visible effect of this RFC and this currently-accepted pattern... trait Tr {}
impl (dyn Tr) { .. } ...is something I'm finding hard to set aside. Elsewhere in the language, we're often trying to offer a parity where if you can write trait Tr {}
impl (impl Tr) { .. } ...and so it seems kind of odd to me that we'd call I also think there's probably a coherent direction we could set out here between this and other pending features like inherent trait impls. But I also want to look into the specialization mental model for this that Niko put forward during the last meeting and give that full consideration. |
@traviscross I'm supportive of the concept of |
That probably points to trying to decide the open question on the other syntax. It's probably a topic for the design meeting we should have on this one. |
Support restricting implementation of individual methods within traits, using the already reserved
final
keyword.This makes it possible to define a trait that any crate can implement, but disallow overriding one of the trait's methods or associated functions.
This was inspired in the course of writing another RFC defining a trait, which wanted precisely this feature of restricting overrides of the trait's method. I separated out this feature as its own RFC, since it's independently useful for various other purposes, and since it should be available to any crate and not just the standard library.
Rendered
Tracking: