# \[Pre-RFC\] Anonymous enum

**URL:** https://internals.rust-lang.org/t/pre-rfc-anonymous-enum/4806
**Category:** language design
**Created:** [February 17, 2017, 8:26pm UTC](https://internals.rust-lang.org/t/pre-rfc-anonymous-enum/4806 "2017-02-17T20:26:14Z")
**Posts on this page:** 11
**Page:** 1

<div class="post-metadata">

### Author: ![plietar](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/plietar/32/2591_2.png) [@plietar](https://internals.rust-lang.org/u/plietar)
#### Post date: [February 17, 2017, 8:26pm UTC](https://internals.rust-lang.org/t/pre-rfc-anonymous-enum/4806/1 "2017-02-17T20:26:14Z")

</div>

Quite often I find the need to return values of different types from a function, where all the possible return types implement some common traits. This comes up frequently with futures, where different code paths need to return a different type of future.

The current approach is to return `Box<Trait>` or define an enum manually and write a forwarding implementation of the correct traits, both of which are suboptimal for different reasons.

* * *

My suggestion is to add an anonymous enum type `(A | B)` which automatically implements every trait which is implemented by both `A` and `B`, but user code is not allowed to match manually on the enum.

```rust
// the enum keyword packs the value into an anonymous enum
let x : (&str | u64) = if cond { enum "Foo" } else { enum 5 };
println!("{}", x); // x implements Display, since both &str and u64 do

```

This fits really well with `impl Trait`, even if they are orthogonal features. In this example, the `handle` function’s real return type is `(future::Map<db::DBQuery, {closure}> | future::FutureResult<String, Error>)`

```rust
fn handle(path: &str) -> impl Future<Item=String, Error=Error> {
    match path {
      // DB::query returns some future with type DBQuery
      "/" => enum self.db.query().map(|data| data.to_string()),
       _ => enum future::finished("404 Not found".to_owned()),
    }
}

```

We can even go a step further, using an anonymous enum as the future’s item type. The real return type is now `( future::Map<(&'static str | DBData), {closure}> | future::FutureResult<(&'static str | DBData), Error>)`

```rust
fn handle(path: &str) -> impl Future<Item=impl Display, Error=Error> {
    match path {
      // DB::query returns some future with type DBQuery
      "/" => enum self.db.query().map(|data| enum data),
       _ => enum future::finished(enum "404 Not found"),
    }
}

```

Yay, no boilerplate and no allocations required !

* * *

Unfortunately, it’s not all as nice as it seems. I ran into issues trying to determine which traits can be automatically implemented, and how.

I initially thought object-safe traits would be fine. Just match on `*self` and call the method on the underlying type. However object-safe traits can still have `where Self: Sized` non object-safe methods which cannot (systematically) be implemented. Since the enum would be `Sized`, it needs to define these methods. Restricting automatically implemented traits to those which only contain “object-safe methods” would exclude `Future` and `Iterator`, defeating the whole point.

For these two traits, all the `where Self: Sized` methods also have a default implementation. Therefore instead of dispatching to the underlying types the default implementation can be used instead. That is how the `impl <T: ?Sized + Future> Future for Box<T>` works for instance. However while it is fine with `Future` and `Iterator` I don’t think prioritising the default implementation over the underlying types’ implementations is desirable in all cases, so it shouldn’t be used for automatic generation of the trait implementations.

There are also non object-safe but very useful traits which could be implemented, albeit maybe not automatically by the compiler. `Clone` and `Into` are some examples.

* * *

Overall I think

- Traits which only have “object-safe methods” (this is a stronger requirement than object-safe trait) can be implemented automatically, `Deref` or `Display` for example
- Trait authors should have a way to provide an implementation manually (`Future`, `Iterator`, `Clone`, `Into`)
- Some traits simply cannot be implemented at all (eg static methods, methods which take two `Self` values)

Note that the manual implementation only needs to be done once per trait, as opposed to once per enum like it is with manually defined enums.

Regarding manual implementation, I’ve been thinking about something like that :

```rust
// Implements Clone for anonymouse enums of any arity
// where all underlying types are Clone
impl <T: Clone> Clone for (T|...) {
  // self has type &(T|...)
  // gets replaced by the real type of the enum during reification
  fn clone(&self) { 
    // Ugly imaginary syntax ahead, please bikeshed
    // v is the underlying value, X the underlying type
    enum_match *self => ref v : X {
      // v.clone() returns an X
      // The enum keyword packs it into a anonymous enum
      enum v.clone()
    }
  }
}

impl <T: Future> Future for (T|...) {
  type Item = T::Item;
  type Error = T::Error;
  fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
    enum_match *self => ref v : X {
      v.poll()
    }
  }

  /* 
   * Rely on default impl for all the other methods of the Future trait,
   * rather than forward to the underlying value. If it wasn't for these
   * methods, the compiler could have generated this impl block
   */
}

```

`enum_match` can only be used in a `impl Trait for (T|...)`

Given anonymous union `(A | B)`, this gets reified into the following

```rust
impl <A, B> Clone for (A | B)
  where A: Clone, B: Clone
{
  fn clone(&self) {
    // enum_match gets expanded into a match with one an arm
    // per underlying type
    match *self {
      (A | B)::A(ref v) => (A | B)::A(v.clone()),
      (A | B)::B(ref v) => (A | B)::B(v.clone()),
    }
}

impl <A, B> Future for (A | B)
  where
    A: Future,
    // Associated types must match
    B: Future<Item=A::Item, Error=B::Error>,
{
  type Item = A::Item;
  type Error = A::Error;
  fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
    match *self {
      (A | B)::A(ref v) => v.poll(),
      (A | B)::B(ref v) => v.poll(),
    }
}

```

Note that this cannot be done in user code, since enums can’t normally be pattern matched on.

Anyway, just some idea I had. I interested to see what people think

---

<div class="post-metadata">

### Author: ![sfackler](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/sfackler/32/9_2.png) [@sfackler](https://internals.rust-lang.org/u/sfackler)
#### Post date: [February 17, 2017, 9:56pm UTC](https://internals.rust-lang.org/t/pre-rfc-anonymous-enum/4806/2 "2017-02-17T21:56:57Z")

</div>

There have been three attempts at something like this over the years that have a lot of interesting discussion attached:

[https://github.com/rust-lang/rfcs/pull/402](https://github.com/rust-lang/rfcs/pull/402)[https://github.com/rust-lang/rfcs/pull/514](https://github.com/rust-lang/rfcs/pull/514)[https://github.com/rust-lang/rfcs/pull/1154](https://github.com/rust-lang/rfcs/pull/1154)

---

<div class="post-metadata">

### Author: ![plietar](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/plietar/32/2591_2.png) [@plietar](https://internals.rust-lang.org/u/plietar)
#### Post date: [February 17, 2017, 10:11pm UTC](https://internals.rust-lang.org/t/pre-rfc-anonymous-enum/4806/3 "2017-02-17T22:11:22Z")

</div>

The biggest difference between my proposal and the previous ones is that the enum can’t be pattern matched, only accessed through traits. That design decision is motivated by `impl Trait` and futures-rs’ design, which weren’t around when these proposals were written.

Tbh I was quite disappointed myself by my proposal when I realised automatic trait dispatch implementation wouldn’t be that simple. I thought I’d still share my thoughts to get some feedback

---

<div class="post-metadata">

### Author: ![Letheed](https://avatars.discourse-cdn.com/v4/letter/l/df705f/32.png) [@Letheed](https://internals.rust-lang.org/u/Letheed)
#### Post date: [February 17, 2017, 11:36pm UTC](https://internals.rust-lang.org/t/pre-rfc-anonymous-enum/4806/5 "2017-02-17T23:36:33Z")

</div>

Is `enum` really needed here? Maybe something simpler would feel more natural:

```rust
let x: some Display = if cond { "Foo" } else { 5 };

```

The anonymous enum becomes an implementation detail, but is there anything that they can express that an existential couldn’t?

---

<div class="post-metadata">

### Author: ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)
#### Post date: [February 18, 2017, 12:30am UTC](https://internals.rust-lang.org/t/pre-rfc-anonymous-enum/4806/6 "2017-02-18T00:30:42Z")

</div>

Stepping back from anonymous enums to this particular use case: the Futures library contains an `Either` future, which is an enum with the behavior you want. I have a PR against futures to add a `left` and `right` combinator to `Future` to make it a bit more ergonomic to use.

However, when I discussed this PR with @aturon he mentioned that, as @Letheed has just suggested, we could implicitly unify multiple types with an anonymous enum when we are trying to evaluate them as an existential. We might not have explicit syntax for creating an anonymous enum, but it would exist as an implementation detail of `impl Trait`.

---

<div class="post-metadata">

### Author: ![stebalien](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/stebalien/32/228_2.png) [@stebalien](https://internals.rust-lang.org/u/stebalien)
#### Post date: [February 18, 2017, 12:54am UTC](https://internals.rust-lang.org/t/pre-rfc-anonymous-enum/4806/7 "2017-02-18T00:54:48Z")

</div>

@Letheed I like the idea but I think the syntax you’re using is a bit too implicit. For one, type ascriptions aren’t really supposed to coerce. I wonder if some form of `unify` keyword would be appropriate:

```rust
let a: some Display = if cond { unify "Foo" } else { unify 5 };

```

---

<div class="post-metadata">

### Author: ![Letheed](https://avatars.discourse-cdn.com/v4/letter/l/df705f/32.png) [@Letheed](https://internals.rust-lang.org/u/Letheed)
#### Post date: [February 18, 2017, 1:24am UTC](https://internals.rust-lang.org/t/pre-rfc-anonymous-enum/4806/8 "2017-02-18T01:24:25Z")

</div>

What about trait objects?

```rust
let a: Box<Display> = if cond { box "Foo" } else { box 5 };

```

Yes, the implicitness is the only downside i’ve found. OTAH it feels natural to use and should be easy to learn/teach. I’d rather we didn’t introduce another keyword if we don’t have to. I could live with it though. It’s just that unless we make the anon enums explicit in Rust (with maybe the pipe for ex.) it seems redundant with the existential quantifier.

---

<div class="post-metadata">

### Author: ![Ixrec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ixrec/32/6754_2.png) [@Ixrec](https://internals.rust-lang.org/u/Ixrec)
#### Post date: [February 18, 2017, 1:47am UTC](https://internals.rust-lang.org/t/pre-rfc-anonymous-enum/4806/9 "2017-02-18T01:47:56Z")

</div>

I have to agree a silent coercion is going too far, but I actually really like this idea, so maybe add just one extra keyword like enum to make it “explicit”?

`let a: enum some Display = if cond { "Foo" } else { 5 };`

```
fn foo() -> enum Some Display {
    if cond { "Foo" } else { 5 }
}
```

---

<div class="post-metadata">

### Author: ![withoutboats](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/withoutboats/32/4560_2.png) [@withoutboats](https://internals.rust-lang.org/u/withoutboats)
#### Post date: [February 18, 2017, 2:25am UTC](https://internals.rust-lang.org/t/pre-rfc-anonymous-enum/4806/10 "2017-02-18T02:25:01Z")

</div>

I don’t agree that “silent coercion” is a problem any more than its a problem that `Box<Trait>` becomes a fat pointer with a vtable.

Coercions are a problem when they let you ‘loose track’ of what type your value is (or worse - though we would never - when they can actually lose information, like a Long coercing to a Double). This is a change in type only insofar as it changes the representation of the type, but its still an `impl Trait`, you can’t do anything with it you couldn’t without the coercion.

---

<div class="post-metadata">

### Author: ![Letheed](https://avatars.discourse-cdn.com/v4/letter/l/df705f/32.png) [@Letheed](https://internals.rust-lang.org/u/Letheed)
#### Post date: [February 18, 2017, 2:38am UTC](https://internals.rust-lang.org/t/pre-rfc-anonymous-enum/4806/11 "2017-02-18T02:38:50Z")

</div>

Agreed. This is exactly what we already do with boxed traits.

---

<div class="post-metadata">

### Author: ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)
#### Post date: [March 25, 2019, 8:27am UTC](https://internals.rust-lang.org/t/pre-rfc-anonymous-enum/4806/12 "2019-03-25T08:27:58Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
