Reputation: 1253
Let's say I have defined a Group
trait with all the group operations. Would it be possible to create a wrapper AGroup
over Group
without having to manually derive all its operations?
Basically, I'd like to have this:
#[derive (Copy, Debug, Clone, Eq, PartialEq, Group)] // How could I derive Group here as well?
struct AGroup<G: Group>(G);
without all this boilerplate:
impl<G: Group> Add for AGroup<G>{
type Output = AGroup<G>;
fn add(self, other: Self) -> Self {
AGroup(self.0 + other.0)
}
}
impl<G: Group> Neg for AGroup<G>{
type Output = AGroup<G>;
fn neg(self) -> Self {
AGroup(-self.0)
}
}
...
Upvotes: 7
Views: 2674
Reputation: 27905
It's not possible in Rust today (as of 1.50) or for the foreseeable future.
You could write a custom derive
macro for Group
. This amounts to writing code that generates the boilerplate, instead of writing the boilerplate itself. It might be worthwhile if you're going to put #[derive(Group)]
on multiple types. But if you only want automatic implementations for AGroup<G>
, it'll probably be much shorter and simpler just to write the boilerplate.
The name of the feature you really want is "delegation". It's been RFCed a couple of times but never accepted (IMO both RFCs have tried to cover too many different use cases and turned out unwieldy). There are concerns about what syntax is the best, how granular delegation should be, and how easily it might be abused to create brittle "inheritance-like" relationships between data structures.
For now, if you cannot find a different design that doesn't require delegation (such as that suggested in Netwave's answer), you should probably bite the bullet and write the delegating impl
s yourself. There are crates such as delegate
and ambassador
that can make certain delegation patterns easier, but I'm not sure if either of them exactly fit what you're trying to do (more evidence that everybody wants a slightly different form of "delegation").
On implementing Deref
, which is occasionally suggested as an alternative to delegation:
Upvotes: 4
Reputation: 42698
You could also just create a method exposing the inner object interface:
pub trait Group {
fn foo(self: &Self){
println!("Called from group")
}
}
#[derive (Copy, Debug, Clone, Eq, PartialEq)] // How could I derive Group here as well?
pub struct AGroup<G: Group>(G);
impl<G: Group> AGroup<G> {
pub fn inner(&self) -> &impl Group {
&self.0
}
}
pub struct Test {}
impl Group for Test {}
fn main( ) {
let a = AGroup( Test {} );
a.inner().foo();
}
Upvotes: 1