Hi!
I'm working with a custom smart-pointer type in Bevy, and we'd like to implement Deref to go from a permissive capability down to a more restricted one. It looks a little like this:
We can't implement Deref for EntityMut, since that could be used to obtain an EntityRef<'a>and an EntityMut<'a> at the same time. What we want to do is something like this:
impl<'w> Deref for EntityMut<'w> {
type Target<'a> = EntityRef<'a>;
fn deref<'a>(&'a self) -> Self::Target<'a>;
}
But this requires adding a generic lifetime to Deref::Target. My question is, is there an existing feature request for this, or some reason why it couldn't be done? Now that GATs have landed, I think this version of Deref would provide the exact same flexibility the current version does, while allowing for the particular use-case I've outlined above.
That makes sense! Thanks for a clear example. I guess the only way something like this could be implemented is by offering some new trait with the GAT, blanket-implementing the new trait for anything that implements Deref, and then using specialization to allow users to manually implement this new trait as well.
Certainly not an easy change! Especially considering specialization isn't stabilized yet.
One notable but subtle problem with GATifying deref is that *place doesn't logically desugar to a simple function call value Deref::deref(&place) like other operators do; it instead corresponds more closely to *Deref::deref(&place) (or DerefMut), producing a place expression at type Deref::Target.
For type/mutability/method inference/resolution to work, it's necessary to know what the type of *place is independent of how that place is used. So if the dereference sugar gets GATified, I expect the only way it actually does so is with something like
trait Deref {
type Target: ?Sized;
type Output<'self>: Deref<Target=Self::Target>
= &'self Self::Target;
fn deref(&self) -> <Self as Deref>::Output<'_>;
}
trait DerefMut {
type Output<'self>: DerefMut<Target=Self::Target>
= &'self mut Self::Target;
fn deref_mut(&mut self) -> <Self as DerefMut>::Output<'_>;
}
where *place iteratively keeps applying derefs until it gets to a place of type Self::Target through a primitive reference type.