This is true, but I also don’t believe it will become a problem in practice.
It is clear to me that given the choice between fn + return Ok(x) and try fn + Ok(x), we should heavily lint in favor of try fn as the idiomatic choice. This eliminates the “analysis paralysis” / “decision fatigue”.
This is debatable. I think the winnings in terms of simple syntax for being generic over Try carriers is important.
Another major benefit, from my perspective is that it removes the noise of Ok and Err, which is just pure plumbing in your computation, and instead allows you to focus on your problem domain. The focus on the problem domain will also show in the code and thus make it more readable. This is fundamentally what monads are about, they get rid of the plumbing. Since we Rust isn’t a pure functional language, monads won’t work well here, so we use something more tailored for Rust.
Furthermore, try scales better. It is just one annotation at one place; If you have many early return and failure paths, then it can become quite noisy.
Finally, I think this is a case of a major increase to readability globally. While you might not “save more than a few characters” at each point, try fn will (I predict) become so commonplace that the net win becomes quite large.
Here’s an example using try fn and postfix macros to clean up some code from rfcbot real nicely:
impl Team {
try fn validate(&self) -> DashResult<()> {
use domain::schema::githubuser::dsl::*;
let conn = &*(DB_POOL.get()?);
for member_login in self.member_logins() {
let test = githubuser.filter(login.eq(member_login))
.first::<GitHubUser>(conn);
test.unwrap_or! { err =>
error!("unable to find {} in database: {:?}", member_login, why);
throw err
}
}
}
}
This is not a problem. It is easily solved by just allowing any permutation of unsafe const async try.
In terms of BNF:
effect ::= "unsafe" | "const" | "try" | "async" ;
vis ::= "pub" | ... ;
fundecl ::= vis? effect* "fn" ... ;
To make code more uniform and readable, rustfmt will then normalize unsafe const async try into a standard form. But while writing code, it should not be a hindrance.
Would you similarly be fine with typing function instead of fn? The latter only saves 6 characters.
How does it reduce local reasoning and is fallibility-plumbing important for the reasoning? It is true that reasoning becomes function-local instead of expression local, but that hardly seems like a big problem if you don’t write absurdly long functions (but then you have other reasoning problems on your hand…).