Description
I've been asked to make my general concerns about try!
more clear than what #12130 specifically focused on, so I'm going to close that issue and try to do a better job here.
'try' is a short, familiar, and suggestive name. Such names are relatively rare and valuable, and would ideally be reserved for features that reach a high bar of utility and ergonomics. But the try!
macro is, by design, a limited solution to the problem it's put up against, and its limitations are really easy to hit:
- You can't use
try!
frommain
or the proc arg tospawn
, even though you might reasonably expect that 'passing an error up the stack' when there is no 'up the stack' would just fail. - You can't use
try!
for 2 different Result error types in the same fn; you have to switch to another strategy for one or split them out into separate fns. try!
for multiple calls is still verbose and repetitive.
These limitations of course result from its simple implementation using return
from a macro, and when they are brought up, solutions are easy - use unwrap
, write your own macro, just drop the result, fall back to a match expression - and the point is made that try!
was never intended to be a general solution.
But try!
has a big footprint in the ecosystem right now. It has that valuable name. It (as if_ok!
) was the only error-handling technique directly illustrated in the "Handling I/O errors" announcement of IoResult and the removal of conditions. It's the only IO error handling macro that ships in std. It shows up frequently in example code. Regardless of the original intent, it's what people reach for first when trying to figure out how to do IO.
The thing that people reach for first shouldn't have trivial headaches associated with it. The thing that shows up frequently in examples shouldn't instantly blow up when transplanted into users' first programs. Something that ships with std shouldn't require people to throw together a bunch of one-off minor variations of it in their own projects.
Or, conversely, something that has these limitations shouldn't be so visible in the ecosystem.
I don't know what the right alternative is, though I think/hope the general shape of something better would be:
- Wraps a whole block rather just than a statement, to reduce the repetitive verbosity.
- Is an expression, so that it can be moved around/copied from examples/used in more contexts without blowing up.
- Keeps a short, suggestive name.
- Keeps the must-handle warning or a moral equivalent.
I don't think wanting this basic shape amounts to wanting a silver bullet, or to trying to sweep anything under the rug, but if it's just not possible or otherwise not a good idea, I'd be interested to hear why.
The first alternative that pops to mind is a variation of Haskell's do
notation, which other people have discussed elsewhere in more/better detail than I could. There's also the match!
proposal on Reddit right now that may be a candidate. I'm less interested in the exact solution than in convincing the community it's a problem that should be addressed, b/c I'm sure someone else can come up with a better answer than I could.