If only there was some way to propagate the range checks...
let lo, hi = array.bounds()
match lo < hi {
None => array,
Some(lo, hi) => {
let pivot_index = lo.avg_with(hi) // guaranteed to be in bounds
let pivot = array[pivot_index] // never panics, but the index type is opaque, not usize
...rest of the qsort here
}
}
You're still using `array[index]` syntax though. That comes with a panicking branch. The optimizer might elide it, but it might just as well do that in the original code.
I do not believe you've rebutted the main point here. At best what you've done is a show a better way of guaranteeing that indices are correct. But you still need to deal with the fact that index notation comes with a panicking branch.
Not necessarily? Indexing is overloadable, so nothing stops one to write an implementation that'd use an unsafe block without any checks/panics whatsoever (because there are static guarantees that those would be unnecessary).
Apologies for the verbose response, but I just don't see how to avoid it because people constantly get tangled in knots in this sort of discussion.
I think this is continuing to miss the forest for the trees. The original code snippet could also just use `unsafe` to elide the panicking branch and it would still be just as correct while satisfying the requirement that there are no panicking branches.
But what's actually happened is that you've traded "panic when a bug occurs" with "undefined behavior when a bug occurs." Both things are valid choices depending on the circumstances, but the latter is not a realistic escape hatch out of the discussion at hand: whether one should completely elide all panicking branches.
The comment that kicked off this sub-thread:
> IMO (systems programming background), the litmus test for panic! vs. Result doesn’t exist. Don’t panic.
The "Don't panic" advice is correct but ambiguous on its own. If it's referring to the behavior of a program, then yes, absolutely, don't panic. Or as I like say, "if a program panics, it should be considered a bug." But if it's referring the source code, as in, there should be no panicking branches, then that is absolutely wrong. Neither the standard library nor any popular Rust library follows that practice. And they shouldn't.
I interpreted "Don't panic" as the latter meaning because of the claim that "panic! vs Result doesn't exist." That only makes sense in the latter interpretation. In the former interpretation, one does need to contend with a "panic vs Result" choice, as it's often a balance between convenience and how it's usually used. For example, indexing a slice with a `usize` panics.
So either the former interpretation was meant and the poster is confused (or just misspoke), or the latter interpretation was meant and is divorced from reality.
I'll post a link to my blog on this topic yet again, because I'm pretty sure it will clarify the situation and my position: https://blog.burntsushi.net/unwrap
Yes, indeed. And it's not even a novel idea, my example is lifted straight from one of the references of the paper you've linked (namely, Kiselyov & Shan, "Lightweight Static Capabilities", 2007).
I personally think that taking an optimization (e.g. boundary checks elimination) and bringing it — or more precisely, the logic that verifies that this optimization is safe — to the source language-level is a very promising direction of research.