There's two levels of readability involved here.
-
I want a high-level overview of what the code is doing. Here, the
takes_enum(Enum::Variant(EnumVariant { .. }))
is line noise compared totakes_enum(.Variant(_ { .. }))
, becausetakes_enum
is enough context to infer the enum argument, andEnumVariant
is only used for the definition of that one enum variant. -
I want to understand the exact types involved, so that I can locate and edit them as necessary, and trace the exact execution path of the code. Here, having the types spelled out helps.
But I think we should career to 1 over 2. Specifically, because we already have type inference. What is the type of eggs
in let eggs = foo_and_then_bar(&mut spam);
? You don't know until you check the signature of foo_and_then_bar
.
It doesn't hurt the explicitness of Rust to extend inference to the types of arguments. Explicit is not noisy, burdensome, not even local, after all. In addition, Rust does not have function overloading, so it's always clear from the function in question what the type of the argument is (otherwise type inference wouldn't kick in in the first place).
It comes down to that if you elide too much information, your code is harder to read. It's not the language's fault if you do that, though. The inference/elision discussed in these proposals is clearly beneficial in some notable cases (the biggest one being giving us effective kwargs for free and in a backwards compatible way), and when names are too generic, continue to spell out the paths/types/etc.
Does a type in the following example add any useful information to the code useful to understanding what it does? I would argue, no, it doesn't, unless your specific purpose is to edit the type, in which case you'll want to edit the function as well, so jumping to the function first doesn't even add any extra steps.
let call = RemoteCall::from_config(_ {
target: "https://example.com/api",
fallback: "https://example.com/bpi",
timeout: Duration::from_secs(10),
..
})?;
let result = call.submit().await?;
The best typed without new inference placeholders alternative, without adding Ng builder types
let call: RemoteCall = remote_call::Config {
target: "https://example.com/api",
fallback: "https://example.com/bpi",
timeout: Duration::from_secs(10),
..
}.try_into()?;
let result = call.submit().await()?;
Not horrible, but also lacks the power of the dot as well as doc discovery ("I'm on the page for RemoteCall
, but how do I make one?").