Syntatic sugar for enum members inside match


#1

Is there any any syntactic sugar to avoid using the name of the enum every single time inside a match. For example, consider this:

enum Message {
    A,
    B,
    C,
}

struct MyStruct {
  m: Message,
}

fn somevalue(val: &MyStruct) -> i32 {
    match val.m {
        Message::A => 1,
        Message::B => 2,
        Message::C => 3,
    }
}

It is clear that m has to be member of Message. Why is Message needed here?


#2

You can use the individual variants of the enum in your module, to bring them into scope:

use Message::{A, B, C};

enum Message {
    A,
    B,
    C,
}

struct MyStruct {
  m: Message,
}

fn somevalue(val: &MyStruct) -> i32 {
    match val.m {
        A => 1,
        B => 2,
        C => 3,
    }
}

There are a couple of reasons for this behavior, which are spelled out in the RFC that introduced it. One is that it is possible to emulate a flat namespace from a nested namespace, as I demonstrated above; you can always just use use to flatten it out again if you want.

Another is that because many enums have many variants, it can be hard to tell if you have a variant Foo what type it is, and it may also be possible for enum variants to conflict. So in practice, people who use enums would frequently encode the type in the variants in order to make the code more clear; ItemFoo, ExprFoo, etc. For those, it’s nice to just have the language support for it and refer to it as Item::Foo or Expr::Foo instead. With the current situation, people who do prefer the flat namespace can easily just opt-in with use, while you don’t accidentally have conflicts or ambiguities.


#3

For the lazy:

enum Message {
    A,
    B,
    C,
}

struct MyStruct {
  m: Message,
}

fn somevalue(val: &MyStruct) -> i32 {
    use Message::*;
    match val.m {
        A => 1,
        B => 2,
        C => 3,
    }
}

#4

In D language you get an error if there’s an actual shadowing. Otherwise the compiler doesn’t give you an error.

In D there’s the with(), derived probably from Pascal language, that allows you to avoid spelling the struct name if you want to access many of its fields.

This is OK:

struct Foo { int x, y; }
void main() {
    auto f = Foo(10, 20);
    with (f) {
        x++; // OK
        y++; // OK
    }
}

This too is OK, because you aren’t accessing f.x:

struct Foo { int x, y; }
void main() {
    auto f = Foo(10, 20);
    int x;
    with (f) {
        y++; // OK
    }
}

This gives an error:

struct Foo { int x, y; }
void main() {
    auto f = Foo(10, 20);
    int x;
    with (f) {
        x++; // Error
        y++; // OK
    }
}

// Error: with symbol test.Foo.x is shadowing local symbol test.main.x

Perhaps Rust should copy this idea (of how it handles shadowing, not the “with”), to reduce the noise in the code, while keeping the code equally safe and correct.


#5

Am I correct that there is no way to do this if the enum is local to the function containing the match?

fn f() -> i32 {
    enum Foo { A, B }
    use ???;
}

#6

Except that you can put a module inside a function…

fn foo() {
    mod inner {
        enum Foo {A, B}
        pub fn foo() -> Foo {
            use self::Foo::*;
            A
        }
    }

    let x = inner::foo();
}