Compiling playground v0.0.1 (/playground)
warning: bounds on generic parameters are not enforced in type aliases
--> src/lib.rs:3:13
|
3 | type Foo<T: ?Sized> = Cow<'static, T>;
| ^^^^^^
|
= note: `#[warn(type_alias_bounds)]` on by default
help: the bound will not be checked when the type alias is used, and should be removed
|
3 - type Foo<T: ?Sized> = Cow<'static, T>;
3 + type Foo<T> = Cow<'static, T>;
|
warning: `playground` (lib) generated 1 warning
Finished dev [unoptimized + debuginfo] target(s) in 0.76s
What should I do if I want T to include unsized types? Should I just omit the ?Sized bound like in the first Playground?
The Sized trait indicates that the size of this type is known at compile-time; that is, it's not a dynamically sized type. Type parameters are Sized by default, as are associated types. Sized is always implemented automatically by the compiler, not by implementation items. These implicit Sized bounds may be relaxed by using the special ?Sized bound.
Where clauses before the equals sign on a type alias in a trait impl (like type TypeAlias<T> where T: Foo = Bar<T>) are deprecated. Where clauses after the equals sign (like type TypeAlias<T> = Bar<T> where T: Foo) are preferred.
I do not see any note here saying that the type parameters are notSized, or did I miss something? It only states that it cannot include bounds (in the syntax) unless used in a trait. Should the reference be improved in that matter, or did I miss something?
It doesn't say "in the syntax", it just says there can be no bounds. I agree that the documentation is ambiguous, but one can reaonably read it as "type aliases never have any bounds on their parameters". Which, of course, includes any possible default T: 'static or T: Sized bounds.
In other words, a type alias isn't an abstraction boundary. It's just a readable name for the term of the corresponding type. This interpretation, unfortunately, is not quite compatible with the proposed for stabilization impl Trait in type aliases.
While they do use essentially the same syntax, so comparing their behavior is fair, do note that type aliases and associated types are distinct concepts.
From a usage behavior perspective, type alias impl trait is probably closer to an associated type. Ignoring how it gets inferred, you could potentially think of
// opaque type alias
type Tait<'a, T, U> = impl Trait;
as acting similar to
// type projection
trait TaitImpl<'a, T, U> {
type Resolved: Trait;
}
// transparent type alias
type Tait<'a, T, U> = <() as TaitImpl<'a, T, U>>::Resolved;
except still generic over TaitImpl such that you can't use the concrete resolved type, although I'm certain there's details about how lifetime/generics capture works that differ slightly from this simple expansion.
But yeah, there's definitely some unfortunate differences between different places and ways you can write type X =. Personally, I'm still hoping inherent associated types happen eventually. But to the specific point about GATs, the where Self: 'a bound AIUI is currently required such that T-lang can figure out what the consistent behavior of generic and nongeneric associated types should be and hopefully use that in the future.
I think it's not a big deal, but it did surprise me a bit, particularly because the error message didn't say that ?Sized was unnecessary but warned me the bound would not be "checked":
help: the bound will not be checked when the type alias is used, and should be removed
A ?Sized bound isn't really a bound but a relaxation of a default bound. Thus I wasn't entirely sure if I would run into problems with !Sized type parameters (though testing it on Playground revealed that it isn't a problem, even if not described explicitly in the reference).
There is no default Sized bound in general. Sized is just a trait, so the only absolute default is "it's not implemented". However, specifically for generic parameters on ADTs and functions there is a default Sized bound, for ergonomic reasons.
Which is the majority of uses in practice, of course, so it does feel like Sized is some absolute default, but it isn't.