" I have repeatedly asked the Servo developers if they've ever had to think about bounds checking and the answer is that it's not shown up even once in performance profiles."
That's because the problem they're solving isn't array-oriented. Try running LINPACK benchmarks, matrix multiplies, etc.
(Annoyingly, both Go and Rust lack first-class multidimensional arrays. Arrays of arrays are not the same thing.)
I.e. like C++'s eigen or Python's numpy? I'm sure that Rust and Go can take the same approach: implement it in libraries. E.g. https://github.com/bluss/rust-ndarray is a Rust library for it.
I'm sure you'll be sad that this takes `unsafe` to do performantly, but embedding it in the language is no different (the burden of proof just switches from "is this code safe" to "is the code that this code generates safe", and the latter is a harder question).
Not only does that crate use unsafe code, it exports unsafe operations:
unsafe fn uchk_at<'a>(&'a self, index: D) -> &'a A
Perform unchecked array indexing.
Return a reference to the element at index.
Note: only unchecked for non-debug builds of ndarray.
There's no subscript checking optimization for the operations there at all. If you use the safe "at" operation, you get back a "Some" or "None". Here's the basic operation of subscripting:
/// Return a reference to the element at **index**, or return **None**
/// if the index is out of bounds.
pub fn at<'a>(&'a self, index: D) -> Option<&'a A> {
self.dim.stride_offset_checked(&self.strides, &index)
.map(|offset| unsafe {
to_ref(self.ptr.offset(offset) as *const _)
})
}
"I don't see why exposing unsafe operations is problematic: the crate's user still has to explicitly decide to use them if desired."
Duh. The fact that someone felt it necessary to expose unsafe array access to the user indicates that the checking optimization has an overhead problem.
I struggle to believe that subscript checking can be automatically removed in arbitrary code in any language (at least, not without full dependent typing), e.g. it seems pretty hard to make guarantees about something like x[y[i]] with arbitrary y.
That's because the problem they're solving isn't array-oriented. Try running LINPACK benchmarks, matrix multiplies, etc.
(Annoyingly, both Go and Rust lack first-class multidimensional arrays. Arrays of arrays are not the same thing.)