Hacker News new | past | comments | ask | show | jobs | submit login

Maybe it shouldn't have but developing in Rust would be intolerable without .unwrap(). In the real world you wade through API documentation figuring out the types and colors of functions while forever being assaulted by Result<>. Without .unwrap() your progress would be destroyed as you'd have to immediately deal with every unhappy path. unwrap() allows you nail together the happy path and then revisit the failure modes after you get your intentions working.

Also, .unwrap() is fine for unit test mocking you need in real world code.

Are irresponsible and/or under-resourced programmers abusing .unwrap()? Yes. Obviously. Fortunately, the frictionless .unwrap() makes this blatantly obvious to everyone else (just as profligate use of unsafe {} does,) so detecting crap code is much easier. This is a vast improvement over traditional 'systems' languages that permit said programmers to ignore failures without so much as a word.

The net result is .unwrap() is a win for Rust.




The downside is that the "revisit the failure modes" step never happens.

I've worked on C++ projects with a programmer who commented out "-Wall" with the comment "No one has time for that" (and then I enabled it and spent a couple days with valgrind tracking down crap that should never have happened). I remember the hate for Java's checked exceptions ("Convert them all to unchecked exceptions and forget about it." -> "Why is the app blowing up in production?").


> The downside is that the "revisit the failure modes" step never happens.

You exaggerate, but yes crap code exists. As I said, however, you can spot it from across the room with grep -r 'unwrap()'. That's all I ask; can work be evaluated easily? Rust doesn't guarantee correctness; thus unsafe{} pragmatically exists. Rust just makes much incorrectness more obvious and easier to detect, both for the coder and for those upon whom their work is foisted.


Programmers who comment out Wall would be even less likely to use Rust if it didn't provide unwrap().


Pretty much all of my non-leaf functions return Result, in application code (or where I can't be bothered to build error types as I go) I'll use anyhow to allow me to coerce pretty much anything into my result type. So unwrap can -- fairly easily -- be replaced by `?`.

I'd still like to be able to agree with the compiler that it can prove that certain error cases don't happen, as with ether an unthinking propagation upwards or an unwrap I'm reliant on my own analysis to assure myself I don't need to explicitly special-case that error. If the compiler is able to dead-code eliminate the unwrap, I'd like to be able to tell the compiler that there's a bug in my code if the unwrap is still in place after optimisation.


> forever being assaulted by Result<>. Without .unwrap() your progress would be destroyed as you'd have to immediately deal with every unhappy path.

I don't know much about Rust but eg. in Haskell you run a Result-returning computation in its monadic context where success continuation/failure propagation is taken care of by the underlying machinery (ie. the implementation of bind), eg.:

  f :: Either Error Stuff
  f = do
    foo <- getFoo ...
    bar <- getBar ...
    ...
Does Rust have something similar?


Rust has std::Result<>, concise operators that comprehend that type, and various popular Result<> wrapper libraries that make the simple cases concise and pleasant to deal with. I love Rust error handling; it is among the best features of the language.

BUT! When dealing with nontrivial cases, particularly with asynchronous code, Result<> can get complicated. Not everything is Copy. Sometimes you have to type erase errors. That chore tends to be a bit of a hairball, as the many StackOverflow cries for help will attest. Other Result<> hairballs exist as well. For one thing it's a bit anemic in the 'original cause' department and sometimes you need to elaborate on it to capture more information about failures.

Coping with these cases is most comfortably done after you've nailed down your intentions and shown yourself that your code and whatever mass of dependencies you're reusing work as intended. Later, when dealing with the failures you papered over with .unwrap() you might end up doing some refactoring. At that point, however, you are confident that your effort will ultimately work.

The brilliance of .unwrap() is that your technical debt is visible. You can spot it in the dark, as can everyone else. In my mind that's a killer feature of Rust. I can't make you write good code, but at least I stand a chance of spotting it when you don't.


That would be the ? operator, I think. It will return the error or continue execution with the data.


> Also, .unwrap() is fine for unit test mocking you need in real world code.

People keep saying this but it is sometimes incredibly frustrating how little people annotate their test failure points in rust unit tests. I would really like to see more people get a little verbose in their tests and use the third arg of the assert macros and .expect with explanations of what the line is trying to prove.


What I have in mind is when your unit test scaffold must populate some collection or whatnot from a file that's part of the code base, or similar legwork. The read might fail somehow but if it does you have bigger problems, so .unwrap() is fine.


That’s why exceptions are superior, in my opinion. Rust’s unwrap is still better than Go’s case, because at least it won’t just silently continue, but all things being equal, exceptions are really great, I don’t get this newfound hate for them.

They are analogous to Result types, just supported at a deeper level, with better default behavior (auto-unwrap and bubble-up) and better debugging (stack-traces).

Though in Rust’s case, I think not having exceptions was a good choice (due to it being a low-level language)


It's because people don't generally understand them. Especially checked exceptions are very difficult to understand if the programmer has not been taught the fundamental principles of how to deal with them (generally, don't, and just let them ripple up by marking your method as throws). Well that, and poorly designed API's in common libraries that forces the programmer to do bad things.

It's very common that the fashion opinions of the day decides that something is bad or suboptimal, and the community reacts by doing the complete opposite, giving us something that may not have the core issue of the original problem, but also lack all of its advantages. A few years later the pendulum then swing back in the other direction.

Examples include the sequence: mainframes (server), desktops (local), webapplications (server), SPA's (local).


Exceptions don't work well in systems languages. That's why, for instance, Google doesn't allow C++ exceptions[1]: "We do not use C++ exceptions." Full stop. Mozilla also follows this policy in Firefox[2]. The moment you start unwinding stacks over calls that are not aligned with your runtime's exception handling regime you're in crazy land and everything goes to pot. This includes all transitive calls however deep they go. Turns out that's unworkable.

Rust designers understood all of this. Exceptions in systems languages are a misfeature that beguile the naïve.

Is there some glorious future system where this is no longer the case? I don't know. Microsoft tried and made an inscrutable mess of it that C++ programmers bang their unhappy heads upon daily. Apple's objective-c had to adopt the C++ ABI for exception handling creating its own proprietary hairball.

No ones done it well yet! The wise find that informative.

[1] https://google.github.io/styleguide/cppguide.html#Exceptions [2] https://firefox-source-docs.mozilla.org/code-quality/coding-...


I explicitly wrote that Rust being a low-level/systems language gets a pass on exceptions.


Respectfully, I didn't reply to you.




Consider applying for YC's W25 batch! Applications are open till Nov 12.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: