Yeah that's an interesting solution, you basically made a trait shortcut which implements other traits with specific implementations. But notice that still the core solution to the problem of recyclable trait implementations is just using ZSTs with the desired implementation.
Personally I feel like the desired solution is the ability for subtraits to override default implementations and implement required methods of their supertraits. And then in the rust docs for each trait you'll see the total required methods to implement on the list on the left to make it clear if the subtrait has already implemented some of the supertraits.
So then code like this will be possible:
trait Account {
fn id(&self) -> u32;
fn from_cookies(&str) -> Self;
}
trait TokenAccount: Account + Deserialize {
fn <Self as Account>::from_cookies(&str) -> Self {
// deserialize stuff here...
}
}
...
struct Account { ... }
impl auth::Account for Account {
fn id(&self) -> u32 { Account.id }
}
impl auth::TokenAccount for Account;
ExactSizeIterator's new implementation with proposed functionality
I can also take the ExactSizeIterator subtrait as an example, it doesn't have any required methods, but the documentation instructs you to override the size_hint implementation of its supertrait, Iterator. So optimized implementations can use the len provided trait method from ExactSizeIterator, that gets its info from size_hint, hopefully improving performance.
I feel like implementing ExactSizeIterator is unclear, and forces you to read the docs. I know this may sound stupid but I feel like having documentation is a privilege, and for the same reason I think documentation should not be required in order to understand how to use something. A language as expressive as Rust should be (and usually is) understandable without documentation in my opinion.
Which is why I think with the proposed subtrait can implement supertrait functionality, ExactSizeIterator should require a len method, which is what the dev implements when implementing ExactSizeIterator, instead of implementing size_hint from Iterator. This len method is instead of the len provided method from ExactSizeIterator that just returns a usize that it gets from the implemented size_hint. But before the "old" len returns the usize, it makes sure with assert_eq! that both of the bounds received from size_hint are equal.
I can see 2 performance gains from this new implementation, ("old" len being the current implementation in std):
- Old
len returns a usize but it gets it from an fn size_hint -> (usize, Option<usize), so memory is wasted from the unneeded bounds. New len just returns a usize because it is the literal ExactSizeIterator implementation.
- Old
len makes sure both the bounds returned from the size_hint are equal, for safety, with assert_eq!. For the same reason as the first performance gain, new len doesn't need to check anything.
old len source code
Maybe the compiler already optimizes away the "faults" I noted with the old len when compiling with optimizations. But I still think it could speed up optimized compilations because there are fewer things to optimize (maybe that's how it works?) and that it will also optimize non-optimized debug builds, of course.
And lastly, because of the proposed functionality, ExactSizeIterator can override size_hint from Iterator in order to keep the old functionality like so:
trait ExactSizeIterator: Iterator {
fn <Self as Iterator>::size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
}
This avoids the boilerplate that there usually is when implementing ExactSizeIterator, where the implementor needs to return (len, Some(len)) from size_hint instead of just len. Though this is very little boilerplate, I imagine it could be much more significant for other traits.
Conclusion
I think this subtrait implement supertrait functionality would be highly beneficial for Rust. And in an unrelated note, I also think in general that there should be the ability to make trait methods private, so they are only accessible to the trait itself and its subtraits. The current solutions I've seen for private trait methods is to have ZSTs that can only be made where it can be called, which is the same module as the trait usually.
I feel like traits are a huge zero cost abstraction yet have such limited functionality, to me they are the core to reusability and modularity. I think they are the biggest (and maybe the only) pillar of polymorphism in Rust and with my proposed subtrait can implement supertrait functionality they will now also offer inheritance (with no expense at runtime, right?).
I am probably getting ahead of myself and people who are far smarter than me who contribute to the language aren't adding this functionality for a reason but I'd like to know why that is and the opinion of anyone who sees this.
Also, sorry about the wall of text.