Currently rustdoc calls these "Aliased Types", but this can can cause some confusion, since a lot of people's intuition is that "Aliased Type" means "the type on the RHS of the type alias statement".
These synthetic types basically show what the type would look like if it was defined on its own, instead of being a type alias.
For example, if we have this:
struct Container<A: Trait>(pub A, pub A);
type MyContainer = Container<MyStruct, MyStruct>;
We can use MyContainer as if it was defined as so:
struct MyContainer(pub MyStruct, pub MyStruct);
My best idea so far is "Effective Type", since its what the type alias effectively behaves as, but I wanted to see if anyone else has a better idea for a more intuitive name.
How about “Effective Type Definition” or “Effective Struct Definition”, since the alias acts as if that struct/enum/union was defined?
I think when something is ambiguous, it is often wise to spend more words on explaining what it is, rather than finding the “perfect” single English word. It might even be reasonable to add a paragraph (the Dyn Compatibility section is precedent for this).
Type Alias MyContainer
type MyContainer = Container<MyStruct, MyStruct>;
...alias doc text here...
Effective Struct Definition
The type alias MyContainer stands for the struct Container, but is used as if it were the following struct definition:
that's because the aliased type is the interface, and the type = line is a implementation. Typically for users of the API the interface is what matters, and how it's been defined may be either reserved for advanced uses, or meant to an implementation detail.
Typically for users of the API the interface is what matters, and how it's been defined may be either reserved for advanced uses, or meant to an implementation detail.
In my experience, for many actual uses of type aliases, the identity of the underlying type very much does matter. For example, in the somewhat common pattern type Result<T> = std::result::Result<T, Error>, it matters that the alias is for the well-known Result type and not any other — if it weren’t, using this would result in many type errors.
Of course, if the documentation says “don’t assume this type alias’s definition is stable, only use it with this API”, then you have to respect that. But cases where that is actually the right design choice vs. an opaque newtype are, I think, rarer than cases where type aliases are used in ways that intentionally expose the equivalence.
This also won’t work with TAIT because there the alias is absolutely the interface and the underlying type is the implementation detail.
Also, type aliases don’t alias the associated value constructor so they’re actually not fully equivalent to the RHS. This is of course something that could be changed, though it would be a backwards incompatible change.
the tuple struct definition implicitly creates the functionfn Foo(_: i32) -> Foo in the value namespace. But the type alias doesn't alias the constructor function:
let a: Bar = Foo(1);
// error[E0423]: expected function, tuple struct or tuple variant, found type alias `Bar`
// note: can't use a type alias as a constructor
let b: Bar = Bar(2);
// using the curly constructor syntax *is* allowed though because the "Bar"
// is looked up in the type namespace here
let c: Bar = Bar { 0: 3 };
The same applies to aliases of unit tuple structs.
You can work around this by aliasing the constructor yourself:
#[allow(non_upper_case_globals)]
const Bar: fn(i32) -> Bar = Foo;
(if the type is generic, you need a delegating function rather than a constant.)