-
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
Rfc: delegation of implementation #1406
Conversation
|
||
## Associated types/constants | ||
|
||
Unless explicitly set associated types and constants should default to the surrogate implementation value of the corresponding items. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How could a type explicitly set associated types different from the surrogate implementation without introducing a type error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will certainly introduce a type error. But if you need diverging associated types there's a high chance you want something more complex than delegation anyway. In that case you will certainly have to provide a specific implementation for most of your methods. The proposed feature is only worth it if the delegating type has a behaviour "similar to" the surrogate type. The more it diverges the less valid the entire approach becomes.
An alternative could be to allow additional delegating expressions for associated types. This would create a bridge between DelegatingType::AssociatedType
and SurrogateType::AssociatedType
and enable the compiler to transform one type into another where required. But in the end I felt that the situations where this would be the expected behaviour might be so specific that I didn't mention that possibility.
How does (partial) delegation interact with default impls?
If Either choice leads to potentially confusing bugs; so maybe we shouldn't support partial delegation, but only full delegation? Are there any other potentially problematic interactions with other features (e.g. specialization)? Also, you should separate the possible extensions ("Inverse delegating expressions", "Combined delegation", "Function-based delegation", "More complex delegation") from the detailed design. I think most of those are not worth the additional complexity. But the core feature idea, |
Thanks for writing this RFC, I agree with the concerns of inheritance overuse, this makes great use of the trait system 👍. The inverse expressions are more complex and it's not clear what |
Very nice. I doubt partial delegation makes sense, as it gets you into inheritance issues, but maybe that's a use case for function delegation, assuming it makes sense. I donno if this ad hoc function delegation is wise either, but if if so maybe functions that could be delegated to could be marked as such, basically making them an anonymous trait. Or maybe this should be done with default impls anyways. Also, combined delegation looks harmless. It's worth being more explicit that this deals with structs and tuple structs (newtypes), but apparently does not cover anonymous tuples, which it might, and maybe say why. Around enums, one might mention in Alternates that deriving mechanisms could potentially do enums, but they are likely heavier and remain an ongoing topic of research in the functional language community : https://stackoverflow.com/questions/3864647/how-does-deriving-work-in-haskell/3864801#3864801 |
Done.
That's a good question. I think the most reasonable approach is to give delegation higher precedence over default impls and specialization in all situations. This rule is simple to understand and IMHO the most compatible with the principle of least astonishment.
To me it is the equivalent of the possibility to override a virtual method in a subclass in the OOP world so I'm not sure on which aspects it could be considered as an issue.
I focused on examples found in existing code which mainly deal with structs. I may miss something but I see no reason why this feature should be limited to a certain kind of type. Basically what you need is something that can support implementations (any type) and an expression to "convert" a type |
In that case, a delegation for an |
Of course. That might not be a very good idea for readability reasons and a preferred approach would certainly be to encapsulate your match inside a function that would be called in the delegating expression. But it should be possible.
I'm not sure exactly about the issue. If the variants of your enum are actually quite different, it naturally implies there is very little chance you can identify a single surrogate type that would make sense. So just don't use delegation at all in that case. However this is a consequence of the semantics of your objects (what your enum and your trait represent) not an issue with the compatibility of delegation and enums. Now if you realize for example that a given enum |
The simple delegation case could be handled by the The derive syntax that could be used can be bikeshedded of course, but simply putting the expression after the type should be readable. #[derive(PartialEq("self.1.abs()")]
struct A(i32, i64); About partial delegation: that sounds more like you actually should split your trait into multiple traits. |
Your remark implies that you owns the trait and can modify it as you want. That's not necessarily true. |
neither am I, but that's currently the only available syntax. Caveat: you can do this in a crate instead of the standard library by using a different name than
True, but my statement still stands, the owner should split it. Rust should not have syntax just for working around bugs in foreign code. |
Not with the current macro system. As I stated earlier, you would need two macro expansion phases. |
May I suggest using |
@anmej How about |
I assume the devs don't want to add new keywords. |
I was reminded of C++11's constructor inheriting. impl<'a> Hash for H<'a> {
use self.name impl;
// can "replace"/override certain method impls
} Or make it By the way, what about enabling the adoption of all of the implementations, e.g. if impl<Rhs> PartialOrd<Rhs> for Thing {
use self.name impl;
} If we only want certain ones then we can write them out explicitly (unless some shorter syntax is proposed, though I'm not necessarily eager to come up with one): // adopt PartialOrd<Foo> and PartialOrd<Bar> implementations
impl PartialOrd<Foo> for Thing {
use self.name impl;
}
impl PartialOrd<Bar> for Thing {
use self.name impl;
} |
As someone currently using C++ and considering Rust for future projects, this looks like it could solve almost all the places I'd actually want to use inheritance. For what it's worth, something like this would go a long way towards attracting me to the language. Definitely +1. |
I have no strong opinion on the exact syntax as long it is short and consistent. I guess not introducing yet another keyword would be desirable.
This is good news. At the same time it shows there is a urgent need for better factoring features before the adoption of inheritance. |
So my major concern is that it seems very difficult to produce useful error message. If the 300 issues tagged with A-diagnostics (the most-used tag) on rust-lang/rust are anything to go by, error messages are frequent source of confusion and problems. And this taking into account that many people praise the high quality of Rust's errors! |
# Summary | ||
[summary]: #summary | ||
|
||
Provide a syntactic sugar to automatically implement a given trait `Tr` using a pre-existing type implementing `Tr`. The purpose is to improve code reuse in rust without damaging the orthogonality of already existing concepts or adding new ones. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/rust/Rust/
(proper noun)
This seems like a great step forward, and I am a big fan of encouraging composition over inheritance. Similar to the concerns about inheritance, I think that I've also started on a compiler plugin to do the same thing and quickly ran into similar issues. You simply don't know the relevant types at the right time of the process. I think that would be the same problem with a @Aatch do you have any specific issues in mind? Conceptually, I'd hope that the errors would basically be the same as if we had a macro that expanded to the |
Character Properties are of different kinds and shapes, and as UNIC components grow, we need a better way to be able to categorize them by their shape, and a way to make sure we have consistent, noncolliding API for them. This is the first step into building a CharProperty taxonomy, with as little as possibly needed to provide the assurances desired. We hope that the implementation can be improved over time with new features added to the language. There's already some proposals in this front. See these discussions for more details: * [Traits as contract, without changes to call-sites](https://users.rust-lang.org/t/traits-as-contract-without-changes-to-call-sites/11938/11>) * [RFC: delegation of implementation](rust-lang/rfcs#1406)
Character Properties are of different kinds and shapes, and as UNIC components grow, we need a better way to be able to categorize them by their shape, and a way to make sure we have consistent, noncolliding API for them. This is the first step into building a CharProperty taxonomy, with as little as possibly needed to provide the assurances desired. We hope that the implementation can be improved over time with new features added to the language. There's already some proposals in this front. See these discussions for more details: * [Traits as contract, without changes to call-sites](https://users.rust-lang.org/t/traits-as-contract-without-changes-to-call-sites/11938/11>) * [RFC: delegation of implementation](rust-lang/rfcs#1406)
Character Properties are of different kinds and shapes, and as UNIC components grow, we need a better way to be able to categorize them by their shape, and a way to make sure we have consistent, noncolliding API for them. This is the first step into building a CharProperty taxonomy, with as little as possibly needed to provide the assurances desired. We hope that the implementation can be improved over time with new features added to the language. There's already some proposals in this front. See these discussions for more details: * [Traits as contract, without changes to call-sites](https://users.rust-lang.org/t/traits-as-contract-without-changes-to-call-sites/11938/11>) * [RFC: delegation of implementation](rust-lang/rfcs#1406)
Character Properties are of different kinds and shapes, and as UNIC components grow, we need a better way to be able to categorize them by their shape, and a way to make sure we have consistent, noncolliding API for them. This is the first step into building a CharProperty taxonomy, with as little as possibly needed to provide the assurances desired. We hope that the implementation can be improved over time with new features added to the language. There's already some proposals in this front. See these discussions for more details: * [Traits as contract, without changes to call-sites](https://users.rust-lang.org/t/traits-as-contract-without-changes-to-call-sites/11938/11>) * [RFC: delegation of implementation](rust-lang/rfcs#1406)
@cramertj Fine. Then my opinion is that the syntax should support these features:
As usual a dedicated keyword is of course clearer (the
@eddyb I would find it pretty obscure not to have similar syntaxes for two variations on the same idea. Additionally the second proposition does not extend very nicely to a list of methods. Why not
|
@contactomorph could you consider signing off to the MIT/Apache 2.0 licensing terms inside this issue: #2096 ? Thanks! |
@aturon @eddyb @nikomatsakis @nrc @pnkfelix @withoutboats would it be possible to add an "Ergonomics Initiative" lavel to this Pull request ? Thank you |
I'm going to move to postpone this RFC. While this remains an important problem the lang team would like to tackle, there remain blocking issues with the RFC as proposed. An effort was started to develop a new, more conservative design, and we'd very much love to see that come to fruition, but at this point it seems highly unlikely to land before the impl period. Thanks, @contactomorph and many, many others for continuing to push on this. @rfcbot fcp postpone |
Team member @aturon has proposed to postpone this. The next step is review by the rest of the tagged teams: No concerns currently listed. Once these reviewers reach consensus, 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! See this document for info about what commands tagged team members can give me. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
I'm going to go ahead and close this out as postponed, given that the impl period has started. I hope folks can pick this back up toward the end of the year! |
😢 |
Today is the end of the year. |
@aturon what is the criterion for reopening this issue to continue discussion? This feature is one of the few ergonomics changes that benefit both new users and existing users without adding much cognitive load. If we want to focus on polishing the language instead of opening other new RFCs this year, this is one of the good candidates. |
Rfc for delegation of implementation