# Some GAT questions (2022-08-23)
## Question Set A
https://github.com/rust-lang/rust/pull/96709#issuecomment-1181931456
poses the following example:
> **The distinction between ensures clauses and where clauses.**
> Given a trait like this:
>
> ```rust
> trait WidgetFactory {
> type Item<T>: Display
> where
> T: Debug;
> }
> ```
>
> The Display bound indicates the impl must prove that Item is Display, but the T: Debug bound must be satisfied at the point where the type F::Item<X> is written (i.e., we must show that X: Debug to reference the GAT). This has led to some confusion in the past, and to some extent this is inherent in the syntax.
First, I *assume* that the above is equivalent to:
```rust
type WidgetFactory {
type Item<T: Debug>: Display;
}
```
Second: Does the above imply that
```rust
type Item<T: Debug>: Display;
```
has different semantics from
```rust
type Item<T: Debug> where Self::Item<T>: Display;
```
## Question Set B
https://github.com/rust-lang/rust/pull/96709#issuecomment-1120050703
has several examples, which pnkfelix has reduced down to the following key observations:
https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=9e8bf78224a44138c0382d984bc86b3e
```rust
#![feature(generic_associated_types)]
pub trait LifetimeGenericConcreteMethod<'a> {
type Item<'c>;
// ~~~~~~~~+~~~~~~
// |
// so far so good; no need to relate 'a and 'c.
//
fn f(&self) -> Self::Item<'static>;
}
pub trait LifetimeGenericConcreteMethodWhereSelf<'a> {
type Item<'c> where Self: 'a;
// ~~~~~~~~+~~~~~~
// |
// required because of just this: \
// ----------+---
fn f(&self) -> Self::Item<'static> where Self: 'a;
}
pub trait LifetimeGenericConcreteMethodWhereItem<'a> {
type Item<'c>;
// ~~~~~~~~+~~~~~~
// |
// look ma, no where clause here
//
fn f(&self) -> Self::Item<'static> where Self::Item<'static>: 'a;
}
pub trait TypeGenericConcreteMethod<'a> {
type Item<T> where T:'a;
// ~~~~+~~~~~
// |
// required because of ...?
//
// (How is this different from LifetimeGenericConcreteMethod?)
//
fn f(&self) -> Self::Item<()>;
}
pub trait TypeGenericParametericMethod<'a> {
type Item<T>;
// ~~~~~~~~~+~~~
// |
// look ma, no where clause here
//
fn f<T>(&self) -> Self::Item<T>; // where Self::Item<T>: 'a;
}
pub trait TypeGenericParametericMethodWhereItem<'a> {
type Item<T>;
// ~~~~~~~~~+~~~
// |
// look ma, no where clause here still
//
fn f<T>(&self) -> Self::Item<T> where Self::Item<T>: 'a;
}
pub trait TypeGenericParametericMethodWhereSelf<'a> {
type Item<T> where Self:'a;
// ~~~~+~~~~~~~~
// |
// required because of this: \
// --------+-----
fn f<T>(&self) -> Self::Item<T> where Self: 'a;
}
```
There are three axes that seem to be significant for reasons I do not yet understand:
1. Sometimes a concrete method will force a where clause on the GAT. Compare
`TypeGenericConcreteMethod` against `TypeGenericParametricMethod`.
2. Sometimes a where clause constraining `Self` in a method will force a
constraint on the GAT, but an analogous where clause constrainting
`Self::Item` in the method does not force any analogous constraint on the
GAT. Compare `TypeGenericParametricMethodWhereSelf` against
`TypeGenericParametericMethodWhereItem`.
3. But also: a lifetime-generic GAT doesn't seem to get any implicit forced
constraint between it and lifetime params attached to its associating trait,
but a *type*-generic GAT does. Compare `LifetimeGenericConcreteMethod`
against `TypeGenericConcreteMethod`.
:::info
*Nota Bene:* Please forgive me if this was all previously spelled out in other documents about GATs. They strike me as discrepancies in the user's experience of the feature, but if there are good reasons for all of these discrepancies, then I guess this is a matter of improving our diagnostics or even changing the surface syntax to make such differences in the static semantic more immediately apparent.
:::