5 ms·
> The one thing that sold me on Rust (going from C++) was that there is a single way errors are propagated: the Result type. No need to bother with exceptions
by zozbot234 2y ago
> The one thing that sold me on Rust (going from C++) was that there is a single way errors are propagated: the Result type. No need to bother with exceptions
This isn't really true since Rust has panics. It would be nice to have out-of-the-box support for a "no panics" subset of Rust, which would also make it easier to properly support linear (no auto-drop) types.
- alexeldeib 2y agothat's kind of a thing with https://docs.rs/no-panic/latest/no_panic/ https://docs.rs/no-panic/latest/no_panic/ or no std and custom panic handlers. not sure what the latest is in the space, if I recall there are some subtleties
- zozbot234 2y agoThat's a neat hack, but it would be a lot nicer to have explicit support as part of the language.
- nicce 2y agoThe problem is with false positives. Even if you clearly see that some function will never panic (but it uses some feature which may panic), compiler might not always see that. If compiler says that there are no panics, then there are no panics, but is it enough to add as part of the language if you need to mostly avoid using features that might panic?
- kbolino 2y agoThat's going to be difficult because the language itself requires panic support to properly implement indexing, slicing, and integer division. There are checked methods that can be used instead, but to truly eliminate panics, the ordinary operators would have to be banned when used with non-const arguments, and this restriction would have to propagate to all dependencies as well.
- josephg 2y agoYes that’s right. The feature really wants compiler support for that reason. The simplest version wouldn’t be too hard to implement. Every function just exports a flag on whether or not it (or any callees) can panic. Then we have a nopanic keyword which emits a compiler error if the function (or any callee) panics. It would be annoying to use - as you say, you couldn’t even add regular numbers together or index into an array in nopanic code. But there are ways to work around it (like the wrapping types). One problem is that implicit nopanic would add a new way to break semver compatibility in APIs. Eg, imagine a public api that just happens to not be able to panic. If the code is changed subtly, it could easily start panicing again. That could break callers, so it has to be a major version bump. You’d probably have to require explicit nopanic at api boundaries. (Else assume all public functions from other crates can panic). And because of that, public APIs like std would need to be plastered with nopanic markers everywhere. It’s also not clear how that works through trait impls.
- selfmodruntime 2y agoYeah, this is how it works with no_std.
- kbolino 2y agoNo? https://godbolt.org/z/jEc36vP3P https://godbolt.org/z/jEc36vP3P As far as I can tell, no_std doesn't change anything with regard to either the usability of panicking operators like integer division, slice indexing, etc. (they're still usable) nor on whether they panic on invalid input (they still do).
- arijun 2y ago`panic` isn’t really an error that you have to (or can) handle, it’s for unrecoverable errors. Sort of like C++ assertions. Also there is the no_panic crate, which uses macros to require the compiler to prove that a given function cannot panic.
- nicce 2y agoI would say that Segmentation Fault is better comparison with C++ :-D
- marcosdumay 2y agoWell, kinda. It's more similar to RuntimeException in Java, in that there are times where you do actually want to catch and recover from them. But on those places, you better know exactly what you are doing.
- josephg 2y agoYou can handle panics. It’s for unrecoverable errors, but internally it does stack unwinding by default like exceptions in C++. You see this whenever you use cargo test. If a single test panics, it doesn’t abort the whole program. The panic is “caught”. It still runs all the other tests and reports the failure.
- swiftcoder 2y ago> but internally it does stack unwinding by default Although as a library vendor, you kind have to assume your library could be compiled into an app configured with panic=abort, in which case it will not do that
- kelnos 2y agoI wish more people (and crate authors) would treat panic!() as it really should be treated: only for absolutely unrecoverable errors that indicate that some sort of state is corrupted and that continuing wouldn't be safe from a data- or program-integrity perspective. Even then, though, I do see a need to catch panics in some situations: if I'm writing some sort of API or web service, and there's some inconsistency in a particular request (even if it's because of a bug I've written), I probably really would prefer only that request to abort, not for the entire process to be torn down, terminating any other in-flight requests that might be just fine. But otherwise, you really should just not be catching panics at all.
- tcfhgj 2y agowould you consider panics acceptable when you think it cannot panic in practice? e.g. unwraping/expecting a value for a key in a map when you inserted that value before and know it hasn't been removed? you could have a panic though, if you wrongly make assumptions
- pdimitar 2y agoI don't speak for anyone else but I'm not using `unwrap` and `expect`. I understand the scenario you outlined but I've accepted it as a compromise and will `match` on a map's fetching function and will have an `Err` branch. I will fight against program aborts as hard as I possibly can. I don't mind boilerplate to be the price paid and will provide detailed error messages even in such obscure error branches. Again, speaking only for myself. My philosophy is: the program is no good for me dead.
- von_lohengramm 2y ago> the program is no good for me dead That may be true, but the program may actually be bad for you if it does something unexpected due to an unforeseen state.
- pdimitar 2y ago
- codedokode 2y agoIt's pretty difficult to have no panics, because many functions allocate memory and what are they supposed to do when there is no memory left? Also many functions use addition and what is one supposed to do in case of overflow?
- nicce 2y agoAdditions are easy. By default they are wrapped, and you can make them explicit with checked_ methods. Assuming that you are not using much recursion, you can eliminate most of the heap related memory panics by adding limited reservation checks for dynamic data, which is allocated based on user input/external data. You should also use statically sized types whennever possible. They are also faster.
- codedokode 2y agoWrapping on overflow is wrong because this is not the math we expect. As a result, errors and vulnerabilities occur (look at Linux kernel for example).
- nicce 2y agoIt depends on the context. Of course the result may cause vulnerabilities if the program logic in bad context depends on it. But yeah, generally I would agree.
- pdimitar 2y agoDon't know about your parent poster but I didn't take it 100% literally. Obviously if there's no memory left then you crash; the kernel would likely murder your program half a second later anyway. But for arithmetics Rust has non-aborting bound checking API, if my memory serves. And that's what I'm trying hard to do in my Rust code f.ex. don't frivolously use `unwrap` or `expect`, ever. And just generally try hard to never use an API that can crash. You can write a few error branches that might never get triggered. It's not the end of the world.
- 2y ago
- johnisgood 2y agoI do not want a library to panic though, I want to handle the error myself.
- int_19h 2y agoLet's say the library panics because there was an out-of-bounds array access on some internal (to that library) array due to a bug in their code. How will you handle this error yourself, and how is the library supposed to propagate it to you in the first place without unwinding?
- johnisgood 2y agoEnsure all bounds and invariants are checked, and return Result<T, E> or a custom error or something. As I said, I do not want a library to panic. It should be up to the user of the library. When I write libraries, I make sure that the users of the library are able to handle the errors themselves. Imagine using some library, but they use assert() or panic() instead of returning an error for you to handle, that would frustrate me.
- bionhoward 2y agoThis is already a thing, I do this right now. You configure the linter to forbid panics, unwraps, and even arithmetic side effects at compile time. You can configure your lints in your workspace-level Cargo.toml (the folder of crates) “”” [workspace.lints.clippy] pedantic = { level = "warn", priority = -1 } # arithmetic_side_effects = "deny" unwrap_used = "deny" expect_used = "deny" panic = "deny" “”” then in your crate Cargo.toml “”” [lints] workspace = true “”” Then you can’t even compile the code without proper error handling. Combine that with thiserror or anyhow with the backtrace feature and you can yeet errors with “?” operators or match on em, map_err, map_or_else, ignore them, etc [1] https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used https://rust-lang.github.io/rust-clippy/master/index.html#un...
- aaronmdjones 2y agoIndent by 4 spaces to get code blocks on HN. Like this
- craftkiller 2y agoYou only need 2 spaces: https://news.ycombinator.com/formatdoc https://news.ycombinator.com/formatdoc
- steveklabnik 2y agoYou only need 2. https://news.ycombinator.com/formatdoc https://news.ycombinator.com/formatdoc > Text after a blank line that is indented by two or more spaces is reproduced verbatim. (This is intended for code.)
- bionhoward 2y agoThank you
- J_Shelby_J 2y agoBut can deny the use of all operations that might panic like indexing an array?