Pre-RFC: flexible `try fn`

I’ll join the „please no“ camp here. Not on particular details, but on the whole direction. Here are the points why I don’t like the proposal (I have bigger problem with the auto-wrapping than with throw, I still believe throw is a mis-nomer, because it hints at exceptions, which is not the case):

  • After all these discussions about error handling, I’m still not persuaded there’s anything that needs fixing deep in the language. Sure, better error types are nice (eg. with ability to downcast). But comparing to any other error handling (exceptions, special-case values (-1), two results), rust’s Result feels the most natural and robust against confusion. Both on the caller and implementer side.
  • Introducing a new keyword is a heavy price for a feature, it makes the language bigger. Introducing a new context is even heavier. Even if there was something to fix, would this really be that important to warrant this kind of artillery? It is already hard to teach Rust (yes, I know what I’m talking about), adding yet another way how to handle errors in there doesn’t help. Explaining „Well, Rust does it differently than “ is generally fine and people take it. Explaining „There are these 2 very differently looking ways, which are basically the same thing under the hood“, people tend to ask why and lose some of the will to learn more, because it sounds crazy.
  • As mentioned, some people find the proposed style more understandable, while others less. But having to read both is much worse than either one, for either side. In other words, if auto-wrapping was the only way, from the beginning, I’d probably oppose adding the explicit style now.
  • I think the editing distance is actually an argument against the feature. If I do such a big change to my function as to make it fallible, I should have to look at all places where it makes a difference, not to miss one. And the editing distance is optimising for easy writing, not reading or debugging.
  • Unlike unsafe and (if I didn’t miss something) async, the proposed try context isn’t strictly extensive. If I take existing code and wrap it inside unsafe, it’ll still compile and do the same. It only unlocks more power. However, try makes the code not compile or even changes the meaning. Having the same code mean something here and something else somewhere else is mentally taxing while reading.
  • Auto-wrapping in complex cases like Option<Option<usize>> or Result<Option<usize>, Option<usize>> will be confusing. The Ok or Some or Err annotation makes the intention explicit and clear.
  • As this is a trait method, the auto-wrapping is a hidden and unmarked conversion. I find that auto-conversions are a bigger source of bugs in C++ programs than null accesses and data races together (usually with less severe consequences, though). Sure, there are some auto-conversions in rust (Deref, trait object coercions…), but these are generally conversions to some type that is kind of view into the real object and the original object still stays unchanged somewhere in the memory. The auto-wrapping has a taste the language does something behind my back and erases some of the trust it gained over the time I use it.
  • There’s no way to express a tail-recursive call (I don’t really talk about the tail-recursive optimisation, only about „just call this function and let it decide“). In other words, with normal function, I can return three things: Err(some_error), Ok(some_value), some_result. Here, I can do either throw some_error, some_value. Note that some_result? is not the same thing. As there’s the ? and implicit auto-wrapping, this runs some arbitrary code, which might in theory be expensive, have side effects, etc.
  • It feels like the proposal tries to make error-handling non-intrusive and out of the way. But to build reliable software, error handling is something that is important and needs the attention. Making it too non-intrusive goes against that, you can forget there’s error handling. This feels in the same general direction as „Lifetimes in Rust are hard to learn at first and annoying. Let’s remove that.“ I enjoy the fact Rust makes me be crystal clear in stating my intentions ‒ make up my mind that I return successfully, in this case. The auto-wrapping is in the „Do what I mean“ direction.
19 Likes