3 ms·
> I'm not sure what this is referring to. The try macro and ? operator are solely for propagation, it doesn't make sense to speak of someone restructuring their
by msbarnett 11y ago
> I'm not sure what this is referring to. The try macro and ? operator are solely for propagation, it doesn't make sense to speak of someone restructuring their code "just to get access" to them. Either you were propagating an error before, or you weren't. And if you weren't propagating it that means that you were handling it, which, if you're capable of doing so, is certainly better than propagating.
It's about ergonomics. The concern is what happens when a junior dev hits some Result<> they don't really know how to deal with. Something like this:
io::stdout().flush().unwrap()
This kind of sucks. The "verb" of this line of code is flush(), and in most languages the verb of a line of code is the last thing on it. It's what people are used to scanning for. .unwrap()s bury it in the middle of the line, which makes code harder to scan for verbs. Additionally, everybody has "unwrap is a code smell" chanted at them by Rust people "in the know".
So I want to make this go away, but there isn't a sensible thing for me to do if the universe is fucked to the point where flush isn't working, so matching on the result feels like enormous overkill because I don't really know what to do with the error.
io::stdout().flush()?
Reads a hell of a lot better. It communicates what I'm actually trying to do more simply, and scans a lot better. Of course, it only works in functions that return Result<>s, because it's a Result propagation mechanism, not a do-or-die mechanism.
So if I'm a junior programmer, coming from some less strict language, a bit confused about all of this and I want code to read the way I expect it to read coming from other languages, I might start sprinkling in ?s every time I have to deal with these "Result" thingys. Of course, then the compiler yells at me because my caller has to unwrap Results, so I sprinkle in some more ?s and change my return type, and then...etc.
Pretty soon every function in the codebase returns a Result<> just so the code stays more readable and they can punt errors to main and exit, like they're used to.
tl;dr I think we're likely to see junior devs using a lot more Result<>s than they need to, because ? is more readable and "don't use unwrap" is Dogma.
- kibwen 11y ago"Don't use unwrap" is only dogma in library code, because ultimately it should be up to the ultimate library consumer (the application) as to whether an erroneous situation should cause the program to exit. Relative to this, unwrapping is perfectly acceptable in application code.
- msbarnett 11y agoThat's a message I'm not sure is getting through to end-users. Eg) plenty of people posting code snippets asking for help in the usual places (/r/rust, the forum, SO) will immediately have 5 commentors jump down their throat if there's an unwrap in sight.
- rkangel 11y ago> Relative to this, unwrapping is perfectly acceptable in application code. Unwrapping may be acceptable in application code - it depends on your application. Specifically it depends on whether you need specific handling of unexpected events. If your program is a 'script' - by which I mean something that executes for a short period of time to perform a series of tasks and then exits - then panicking on an error is a reasonable way of aborting. On the other hand, if it's a daemon, then you will likely want to gracefully handle all error conditions and carry on. I think the issue here is that Rust is primarily used as a systems programming language and usage tends more to fall in the 'daemon' category. In that mentality you handle every error (even if it's just to print something), and that is probably where the general community pointers towards avoiding unwrap come from.
- comex 11y agoFor what it's worth, on Unix writing to stdout (including flushing a buffer) can fail in an extremely common situation: your process was piped to another, which exited before you called flush. (This also causes you to receive SIGPIPE, but Rust blocks SIGPIPE by default.) For example, `head` exits after the requested amount of data was read, and `less` exits immediately when the user presses 'q'. Since neither of those is an error, if you want to be well behaved, you should probably either ignore write errors or (preferably[1]) check for EPIPE in particular and respond by silently exiting - not panicking, which writes to stderr. Not sure how well this generalizes to your broader complaint. One could argue that in general, you really do need to think about errors to write good software, so even if languages with exceptions make it slightly easier to write of code that doesn't, that's actually an antifeature because it encourages sloppiness. But maybe that's overly punitive rather than pragmatic. Still, I don't think the answer is exceptions. [1] preferably because of course other errors are possible, especially if stdout is redirected to a file on disk - but then, in a quick and dirty program, if you ignore errors, you're doing no worse than umpteen million C programs that call printf without checking the return value.
- msbarnett 11y agoSolid point, and flushing a buffer isn't necessarily the best example, other than I think it's an obvious place where a less-than-experienced dev is forced to deal with a Result they don't know what to do with and might turn to a beguilingly simple operator that seems to make the problem go away but encourages them to just keep punting Results up the call stack. But you could make the case that I'm being overly pessimistic in focusing on the worst case mess that could be made with this feature.