[Pre-RFC] Inferred Enum Type

This, in fact, already works with inference today in stable. We just don't have special syntax for it.

Here's a demo: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ed060cd13f013414f43985b027053776

mod foo {
    mod bar { 
        #[derive(Default, Debug)]
        pub struct RequestOptions {
            pub value: i32,
            pub other: i32,
        }

        pub fn make_call(url: &str, options: RequestOptions) {
            dbg!((url, options));
        }
    }

    pub use bar::make_call; // Notably *not* importing `RequestOptions`
}

fn main() {    
    // This fails, because we can't name it at this scope:
    //let x = foo::bar::RequestOptions { value: 10, other: 20 };
    
    // But we can create it, and set fields, using the magic of inference:
    foo::make_call("YAY", {
        let mut tmp = Default::default();
        if false { tmp }
        else {
            tmp.value = 123;
            tmp.other = 456;
            tmp
        }
    });
}

Isn't this true for basically all cases of inference, though? Even something like foo(x.into()) is doing it.

I used to think that I needed to annotate all of my local variables, since if I didn't I wouldn't know what they were and they might be something I didn't expect. But I've since gotten used to auto and var and let, and found that I was worrying for nothing.

To take something from C#, I don't know what response.GetHeaders() returns. Maybe it's called TypedHeaders, maybe it's called HeaderDictionary, whatever. If I can still do .RetryAfter = TimeSpan.FromSeconds(5); on it, that's fine my me. (Any change would be semver-breaking, so that's not going to happen outside a major version upgrade anyway, but even then if setting the property on it works, the odds of me actually breaking at runtime while still compiling by it being another type are tiny.)

Or for another thing that works fine in rust already, I could do

response.update_headers(|x| {
    x.retry_after = Duration::from_secs(5);
});

without typing the name of that type nor having it in scope, but still being able to set fields on it.

So I just don't see this as having any more "spooky at a distance" than inference already has in lots of places in Rust. Is there something specific you're thinking would make this case particularly-bad?


Actually, I really like that closure example. It gives a nice TLDR:

Since I could easily make this work:

client.call(|m| m.get, "https://rust-lang.org", |o| { o.max_retries = 4; });

What's really so bad about

client.call(.Get, "https://rust-lang.org", .{ max_retries: 4 });

?

(Or client.call(_::Get, "https://rust-lang.org", _ { max_retries: 4 }); or whatever the syntax.)

4 Likes