Better name for the synthetic types generated for type aliases

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.

1 Like

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:

struct MyContainer(pub MyStruct, pub MyStruct);

Implementations

...

4 Likes

I would probably hide that paragraph behind a dropdown or tooltip, but yeah otherwise this looks good.

I'd swap these around, and display as:

Type Alias

struct MyContainer(pub MyStruct, pub MyStruct);

Type Alias Definition

type MyContainer = Container<MyStruct, MyStruct>;

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.

4 Likes

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.

value constructor? can you elaborate?

In

struct Foo(i32);
type Bar = Foo;

the tuple struct definition implicitly creates the function fn 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.)

1 Like