RFC: Associated type bounds of form MyTrait<AssociatedType: Bounds>
by Centril · Pull Request #2289 · rust-lang/rfcs (original) (raw)
@burdges It depends on what you wish to communicate.
Consider: where X: Family<Assoc<T>: Bound>
. I would translate this to the bounds X: Family
and X::Assoc<T>: Bound
.
Consider: where X: for<T> Family<Assoc<T>: Bound>
. I would translate that to the bounds: X: Family
and for<T> X::Assoc<T>: Bound
.
These two bounds are clearly different (even if the latter builds upon the combination of for<T>
and Family<Assoc<T>: Bound>
). The former talks about a specific T
applied to Assoc
satisfying Bound
while the latter says that for any T
you pick, T
applied to Assoc
, Assoc<T>
satisfies Bound
.
At this point; I think it is too early to introduce Assoc<T>: Bound
given that GATs are not even in the nightly compiler. Once we gain more experience we can see if this extension is worthwhile;
Regarding Family<Assoc: Bound>
as sugar for for<T> Family<Assoc<T>: Bound>
, I think that this would be surprising if we don't have HKTs. If however we do introduce HKTs, this would translate to Functor (AssocFunctor MyFamily)
(as a concrete example) in Haskell. Then I do think it makes sense. But this addition is premature.
EDIT: Actually, no... that was wrong! I don't see Family<Assoc: Bound>
, where Assoc
is higher kinded, meaning for<T> Family<Assoc<T>: Bound>
because in the case of HKTs, it is the functor that has the bound, and not the functor applied to some type argument.
Regarding Trait<Assoc = impl Bounds>
, the meaning depends on if it is in argument position or return position. If it is in return position, that is: -> impl T<A = impl B>
, then the type of A
is existential as seen in this example:
fn foo() -> impl Iterator<Item = impl Clone> { ::std::iter::empty::() }
Therefore, the callee picks the type of Item
.
If however you have impl T<A = impl B>
in argument position, you get:
fn bar(mut iter: impl Iterator<Item = impl Clone>) { let x: Option<()> = iter.next(); }
However; this snippet does not compile because the caller, and not the callee, gets to pick the type, and so we get:
10 | let x: Option<()> = iter.next(); | ^^^^^^^^^^^ expected (), found type parameter