Short enum variant syntax in some cases

TypeScript V.4.1 seems interesting:

But I think they are blowing their complexity budget (the "It fits my brain" old Python motto). TypeScript feels not easy to understand now.

After reading that article I think I'd still like to have a shorter Rust syntax to pass enum variants to functions (without importing then all in the module scope), like:

enum VerticalAlignment { Top, Middle, Bottom }
enum HorizontalAlignment { Left, Center, Right }

fn foo() {
    set_alignment(VerticalAlignment::Top, HorizontalAlignment::Left);
    set_alignment(_::Top, _::Left);
}
4 Likes

That looks good. Swift also has this feature: it would be .Top and .Left. See "dot syntax" at https://docs.swift.org/swift-book/LanguageGuide/Enumerations.html.

A related syntax change suggestion for structs is:

struct Foo(u32);

fn bar1(f: Foo) {} // Current syntax
fn bar2(Foo(x): Foo) {} // Current syntax to get x
fn bar3(Foo(x): _) {} // Shorter and more DRY

Somewhere Centril was suggesting that with generalized type ascription then f: Foo in arguments just becomes a pattern with type ascription, then we can generalize function arguments to support any unambiguous pattern, so fn bar3(Foo(x)) would be valid as it's unambiguously an argument of type Foo.

5 Likes

Various permutations of this (enum::Foo, also allowing _ { x: 5 } for structs, etc) come up regularly. Here's a nice summary comment, though it was concentrated more on use in patterns that in calls.

I'd definitely like something here, ideally both for enums and structs. I think the stumbling block is mostly finding a syntax that makes people happy, and potentially naming convention impacts -- _::Yes is clearly poor, but a reasonable enum to make today if it's usually passed as UseCookies::Yes.

6 Likes

I'd very much like to see this exact syntax.

1 Like

Implicitly "importing" enum variants (and potentially other types?) for fn arguments might be an interesting ergonomic win by reducing verbosity and eliminating the need to have use statements, but I personally find that kind of implicitness distasteful, simply because it breaks my code navigation workflow of grepping for the use statement to figure out where the definition is. "Go to definition" using rust-analyzer and RLS makes up for it, but it also makes it harder for any one without tooling, and almost impossible for people that don't know about the ergonomic rule (where they would just have to look for the function's definition).

Beyond those concerns, I would also wish to perform extensive testing to see what the behavior would be in cases of common mistakes, name clashes, typos, privacy errors, etc. for something like that.

Finally, I would have to say that yes, this would be really nice, making it only for enum variants might be reasonable, if inconsistent. The big advantage of this approach is that it side-steps the "syntax" conversation entirely. Another disadvantage is that this is not generalizable to the "inferred struct" feature (_ { foo, bar }).

2 Likes

It'd also be nice to have the same inference syntax for structs. As an example, every rusoto function has a corresponding structure, resulting in calls that look like this:

ec2.describe_launch_template_versions(
    rusoto_ec2::DescribeLaunchTemplateVersionsRequest {
        launch_template_id: ...,
        ..Default::default()
    }
)

I'd love to write that like this:

ec2.describe_launch_template_versions(_ {
    launch_template_id: ...,
    ..Default::default()
})
2 Likes

Absolutely. I think just that change would immediately be a huge help for being able to use structs for many-argument functions and help sidestep the named argument conversations.

In the mean time, for the Default case you can use a macro trick:

macro_rules! s {
    ( $($i:ident : $e:expr),* ) => {
        {
            let mut temp = Default::default();
            if false {
                temp // this tricks inference into working
            } else {
                $(
                    temp.$i = $e;
                )*
                temp
            }
        }
    }
}

fn main() {
    let x: Foo = s! { y: 4 };
    dbg!(x);
}

#[derive(Debug, Copy, Clone, Default)]
struct Foo {
    x: i32,
    y: i32,
}

https://play.rust-lang.org/?edition=2018&gist=d449857a1d6c317ed4fe16dc09c2dee7

3 Likes