It seems like you can use Generic Associated Types to get the exact functionality that Higher Ranked Trait Bounds provide, with a little extra type-level indirection. Or without (all of) the jargon, you can use #![feature(generic_associated_types)]
to be generic over using Rc
or Arc
, so long as you're okay with using Type<RcProvider>
rather than Type<Rc>
.
#![feature(never_type)]
#![feature(generic_associated_types)]
#![allow(incomplete_features)]
/*!
We want:
```not_rust
struct UsesRc< R: { Arc or Rc } > {
inner: R< u32 >,
}
```
Unfortunately, this requires higher kinds...
or does it?
GAT can be used to get this exact behavior,
if you squint a little...
*/
use std::{rc::Rc, sync::Arc, ops::Deref};
pub trait RProvider {
type R<T>: Deref<Target=T> + Clone;
}
pub struct RcProvider(!);
pub struct ArcProvider(!);
impl RProvider for RcProvider {
type R<T> = Rc<T>;
}
impl RProvider for ArcProvider {
type R<T> = Arc<T>;
}
pub struct UsesRc< R: RProvider > {
pub inner: R::R< u32 >,
}
Is there something I'm missing that makes "full" HRTB more powerful than GAT, or is this actually just HRTB-behind-type-indirection? (One downside of GAT-as-HRTB is that that the provider indirection structs have to be actively defined by the implementer of the trait for coherence to work out. Full HRTB wouldn't need the extra type, thus sidestep that extra coherence check.)