Skip to content

Commit 1c851e0

Browse files
authored
Merge pull request #2338 from djc/type-alias-enum-variants
Type alias enum variants
2 parents 90a6f4e + 7499ac5 commit 1c851e0

File tree

1 file changed

+120
-0
lines changed

1 file changed

+120
-0
lines changed

text/2338-type-alias-enum-variants.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
- Feature Name: `type_alias_enum_variants`
2+
- Start Date: 2018-02-15
3+
- RFC PR: [rust-lang/rfcs#2338](https://github.com/rust-lang/rfcs/pull/2338)
4+
- Rust Issue: [rust-lang/rust#49683](https://github.com/rust-lang/rust/issues/49683)
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
This RFC proposes to allow access to enum variants through type aliases. This
10+
enables better abstraction/information hiding by encapsulating enums in aliases
11+
without having to create another enum type and requiring the conversion from
12+
and into the "alias" enum.
13+
14+
# Motivation
15+
[motivation]: #motivation
16+
17+
While type aliases provide a useful means of encapsulating a type definition in
18+
order to hide implementation details or provide a more ergonomic API, the
19+
substitution principle currently falls down in the face of enum variants. It's
20+
reasonable to expect that a type alias can fully replace the original type
21+
specification, and so the lack of working support for aliased enum variants
22+
represents an ergonomic gap in the language/type system. This can be useful in
23+
exposing an interface from a dependency to library users while "hiding" the exact
24+
implementation details. There's at least some evidence that people have asked
25+
about this capability before.
26+
27+
Since `Self` also works as an alias, this should also enable the use of `Self`
28+
in more places.
29+
30+
# Guide-level explanation
31+
[guide-level-explanation]: #guide-level-explanation
32+
33+
In general, the simple explanation here is that type aliases can be used in
34+
more places where you currently have to go through the original type definition,
35+
as it relates to enum variants. As much as possible, enum variants should work
36+
as if the original type was specified rather than the alias. This should make
37+
type aliases easier to learn than before, because there are fewer exceptions
38+
to their applicability.
39+
40+
```rust
41+
enum Foo {
42+
Bar(i32),
43+
Baz { i: i32 },
44+
}
45+
46+
type Alias = Foo;
47+
48+
fn main() {
49+
let t = Alias::Bar(0);
50+
let t = Alias::Baz { i: 0 };
51+
match t {
52+
Alias::Bar(_i) => {}
53+
Alias::Baz { i: _i } => {}
54+
}
55+
}
56+
```
57+
58+
# Reference-level explanation
59+
[reference-level-explanation]: #reference-level-explanation
60+
61+
If a path refers into an alias, the behavior for enum variants should be as
62+
if the alias was substituted with the original type. Here are some examples of
63+
the new behavior in edge cases:
64+
65+
```rust
66+
type Alias<T> = Option<T>;
67+
68+
mod foo {
69+
pub use Alias::Some;
70+
}
71+
72+
Option::<u8>::None // Not allowed
73+
Option::None::<u8> // Ok
74+
Alias::<u8>::None // Not allowed
75+
Alias::None::<u8> // Ok
76+
foo::Some::<u8> // Ok
77+
```
78+
79+
This is the proposed handling for how to propagate type arguments from alias
80+
paths:
81+
82+
* If the previous segment is a type (alias or enum), the variant segment
83+
"gifts" its arguments to that previous segment.
84+
* If the previous segment is not a type (for example, a module), the variant
85+
segment treats the arguments as arguments for the variant's enum.
86+
* In paths that specify both the alias and the variant, type arguments must
87+
be specified after the variant, not after the aliased type. This extends the
88+
current behavior to enum aliases.
89+
90+
# Drawbacks
91+
[drawbacks]: #drawbacks
92+
93+
We should not do this if the edge cases make the implemented behavior too
94+
complex or surprising to reason about the alias substitution.
95+
96+
# Rationale and alternatives
97+
[alternatives]: #alternatives
98+
99+
This design seems like a straightforward extension of what type aliases are
100+
supposed to be for. In that sense, the main alternative seems to be to do
101+
nothing. Currently, there are two ways to work around this:
102+
103+
1. Require the user to implement wrapper `enum`s instead of using aliases.
104+
This hides more information, so it may provide more API stability. On the
105+
other hand, it also mandates boxing and unboxing which has a run-time
106+
performance cost; and API stability is already up to the user in most other
107+
cases.
108+
109+
2. Renaming of types via `use` statements. This provides a good solution in the
110+
case where there are no type variables that you want to fill in as part of
111+
the alias, but filling in variables is part of the motivating use case for
112+
having aliases.
113+
114+
As such, not implementing aliased enum variants this makes it harder to
115+
encapsulate or hide parts of an API.
116+
117+
# Unresolved questions
118+
[unresolved]: #unresolved-questions
119+
120+
As far as I know, there are no unresolved questions at this time.

0 commit comments

Comments
 (0)