# \`\_\` for enum

**URL:** <https://internals.rust-lang.org/t/for-enum/17289>\
**Category:** language design\
**Created:** [August 29, 2022, 2:00am UTC](https://internals.rust-lang.org/t/for-enum/17289 "2022-08-29T02:00:59Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![doki23](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/doki23/32/9347_2.png) [@doki23](https://internals.rust-lang.org/u/doki23)\
**Post date:** [August 29, 2022, 2:00am UTC](https://internals.rust-lang.org/t/for-enum/17289/1 "2022-08-29T02:00:59Z")

</div>

I have some code like

```rust
fn used_columns(&self) -> ColumnSet {
        match self {
            Scalar::BoundColumnRef(scalar) => scalar.used_columns(),
            Scalar::ConstantExpr(scalar) => scalar.used_columns(),
            Scalar::AndExpr(scalar) => scalar.used_columns(),
            Scalar::OrExpr(scalar) => scalar.used_columns(),
            Scalar::ComparisonExpr(scalar) => scalar.used_columns(),
            Scalar::AggregateFunction(scalar) => scalar.used_columns(),
            Scalar::FunctionCall(scalar) => scalar.used_columns(),
            Scalar::CastExpr(scalar) => scalar.used_columns(),
            Scalar::SubqueryExpr(scalar) => scalar.used_columns(),
        }
    }

```

Is it possible to provide a sugar like `Enum::_(x) => x.func()`?

---

<div class="post-metadata">

**Author:** ![8573](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/8573/32/4913_2.png) [@8573](https://internals.rust-lang.org/u/8573)\
**Post date:** [August 29, 2022, 3:25am UTC](https://internals.rust-lang.org/t/for-enum/17289/2 "2022-08-29T03:25:26Z")

</div>

Can `ambassador` do what you want?

> **[ambassador](https://lib.rs/crates/ambassador)**
>
> Trait implementation delegation via procedural macros

---

<div class="post-metadata">

**Author:** ![hyeonu](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/hyeonu/32/2162_2.png) [@hyeonu](https://internals.rust-lang.org/u/hyeonu)\
**Post date:** [August 29, 2022, 3:26am UTC](https://internals.rust-lang.org/t/for-enum/17289/3 "2022-08-29T03:26:08Z")

</div>

Have you tried the [enum\_dispatch](https://docs.rs/enum_dispatch/latest/enum_dispatch/) crate?

---

<div class="post-metadata">

**Author:** ![dlight](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dlight/32/8462_2.png) [@dlight](https://internals.rust-lang.org/u/dlight)\
**Post date:** [August 29, 2022, 5:16am UTC](https://internals.rust-lang.org/t/for-enum/17289/4 "2022-08-29T05:16:36Z")

</div>

One option is to write something like

```rust
enum X {
    A(i32),
    B(i32),
    C(i32),
}

fn f(x: X) -> i32 {
    match x {
        X::A(y) | X::B(y) | X::C(y) => y,
    }
}

```

[(playground)](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=57026e7b775f6c463962a030e58191a6)

Then your proposal would be to have `X::_(y)` to expand to `X::A(y) | X::B(y) | X::C(y)`. Which is probably not great because, what if I add another enum variant that doesn't have the same parameters? Like

```rust
enum X {
    A(i32),
    B(i32),
    C(i32),
    D(String, String),
}

```

Then suddenly `X::_(y)` can't be used anymore!

---

<div class="post-metadata">

**Author:** ![dlight](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dlight/32/8462_2.png) [@dlight](https://internals.rust-lang.org/u/dlight)\
**Post date:** [August 29, 2022, 8:00am UTC](https://internals.rust-lang.org/t/for-enum/17289/5 "2022-08-29T08:00:36Z")

</div>

What I'm thinking is that perhaps we should have pattern aliases, something like

```rust
pattern EveryX(y) = X::A(y) | X::B(y) | X::C(y);

fn f(x: X) -> i32 {
    match x {
        EveryX(y) => y,
    }
}

```

Haskell has something like this [pattern synonyms · Wiki · Glasgow Haskell Compiler / GHC · GitLab](https://gitlab.haskell.org/ghc/ghc/-/wikis/pattern-synonyms)

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [August 29, 2022, 9:52am UTC](https://internals.rust-lang.org/t/for-enum/17289/6 "2022-08-29T09:52:44Z")

</div>

It's relatively common to have a method on the type returning an `Option` that acts as a proxy for a multi-variant pattern

```rust
enum Foo { Bar(usize), Baz(usize), Qux }

impl Foo {
  fn as_usize(&self) -> Option<&usize> {
    match self {
      Self::Bar(value) => Some(value),
      Self::Baz(value) => Some(value),
      Self::Qux => None
    }
  }
}

```

(or even single-variant patterns, just to transform into `Option`, though now that we have `if let` those are likely less useful, other than being able to `?` them sometimes).

---

<div class="post-metadata">

**Author:** ![Ryan1729](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ryan1729/32/4770_2.png) [@Ryan1729](https://internals.rust-lang.org/u/Ryan1729)\
**Post date:** [August 29, 2022, 7:12pm UTC](https://internals.rust-lang.org/t/for-enum/17289/7 "2022-08-29T19:12:51Z")

</div>

> [@dlight](#):
>
> What I'm thinking is that perhaps we should have pattern aliases, something like
> 
> ```rust
> pattern EveryX(y) = X::A(y) | X::B(y) | X::C(y);
> 
> fn f(x: X) -> i32 {
> match x {
> EveryX(y) => y,
> }
> }
> 
> ```

A macro can do something similar to this today, for at least this use case:

```rust
macro_rules! every_x {
    ($y: ident) => {
        X::A($y) | X::B($y) | X::C($y)
    }
}

fn f(x: X) -> i32 {
    match x {
        every_x!(y) => y,
    }
}

```

[(playground)](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=69668c3da91c09d81784ad0fe2617c9f)

Would an additional pattern aliases feature allow anything that is not possible with a macro?

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [August 29, 2022, 7:22pm UTC](https://internals.rust-lang.org/t/for-enum/17289/8 "2022-08-29T19:22:19Z")

</div>

This is a design choice, but if _every_ `enum Scalar` variant has exactly the same data, that suggests to me that it should really be a `struct Scalar` with direct fields and a data-less enum `kind: ScalarKind`. Then you can also be sure that the compiler doesn't have to optimize away all the matching when you access the common data.

---

<div class="post-metadata">

**Author:** ![doki23](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/doki23/32/9347_2.png) [@doki23](https://internals.rust-lang.org/u/doki23)\
**Post date:** [August 30, 2022, 3:17am UTC](https://internals.rust-lang.org/t/for-enum/17289/9 "2022-08-30T03:17:10Z")

</div>

> [@dlight](#):
>
> What I'm thinking is that perhaps we should have pattern aliases, something like

But we have to write many patterns for every enum like this. And if I only have one method to do this thing, I just need move the pattern's code into that method.

---

<div class="post-metadata">

**Author:** ![dlight](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dlight/32/8462_2.png) [@dlight](https://internals.rust-lang.org/u/dlight)\
**Post date:** [August 30, 2022, 3:19am UTC](https://internals.rust-lang.org/t/for-enum/17289/10 "2022-08-30T03:19:45Z")

</div>

the problem of doing this with a macro is that if you refactor the type to for eg. remove a variant or change its payload, the type error will confusingly happen in the function that calls the macro, and not in the pattern definition itself.

It's like the difference between Rust generics and C++ templates.

---

<div class="post-metadata">

**Author:** ![Ryan1729](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ryan1729/32/4770_2.png) [@Ryan1729](https://internals.rust-lang.org/u/Ryan1729)\
**Post date:** [August 30, 2022, 6:42am UTC](https://internals.rust-lang.org/t/for-enum/17289/11 "2022-08-30T06:42:14Z")

</div>

Good point. It certainly seems like it would be easier to have high quality error messages if there were a specific syntax for pattern aliases.

---

<div class="post-metadata">

**Author:** ![ruifengx](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ruifengx/32/8594_2.png) [@ruifengx](https://internals.rust-lang.org/u/ruifengx)\
**Post date:** [September 3, 2022, 12:03pm UTC](https://internals.rust-lang.org/t/for-enum/17289/12 "2022-09-03T12:03:07Z")

</div>

> [@Ryan1729](#):
>
> Would an additional pattern aliases feature allow anything that is not possible with a macro?

IMHO this is not always a valid objection. Generics could also be replaced by macros (consider templates in C++), and there are good reasons why we don't go that way. Pattern synonyms can have their own signatures which are validated by the compiler, and when we encounter them in pattern position (e.g., in a `match` expression), the syntax should be exactly the same as normal patterns, so we know what to expect; but for macros, anything could happen in a macro invocation, because the syntax is not pre-determined and enforced by a compiler.

Together with something like [ViewPatterns in Haskell](https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/view_patterns.html) it would become very useful e.g. for high-quality Rust bindings for existing libraries. Consider for example we want a high-level binding for LLVM with the ability to pattern match on its internal IR structures, it could be done by providing a series of accessor functions `try_get_VariantX_from_EnumY: fn(&EnumY) -> Option<&VariantX>` (backed by the foreign implementation), and define `EnumY::VariantX` as a (refutable) view pattern using that accessor function. Additionally with opaque types it would be possible to work with foreign libraries just like normal Rust libraries.

---

<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:** [December 2, 2022, 12:03pm UTC](https://internals.rust-lang.org/t/for-enum/17289/13 "2022-12-02T12:03:15Z")

</div>

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