And there are cases where it is desirable to use unsafe indexing (beyond implementing the standard library iterators). While LLVM is able to get rid of nounds-checking for a simple indexing loop, it's less likely to do in other circumstances. For example, a high-performance sorting function might want to use (some) unsafe indexing. The access patterns and loop exit conditions can be very complex, and LLVM will not be clever enough to reliable optimize out bounds checks.
This may be a problem with the existing compiler, if the Rust implementation is mostly a front-end to LLVM. I'd hate to see "unsafe" code baked into the language standard, though. C++ tried to fix the mess underneath with template libraries. That didn't end well.
"Giving programmers low-level tools when they need them" as an excuse for abandoning language safety is a recipe for bad code. There's a long, long history of that not working. "Unsafe" code should be very, very rare, used for dealing with device registers and such.
This sounds like designing buffer overflows into Rust.
Actual code implementing the `[]` operator for arrays ("slices"):
fn index(&self, &index: &uint) -> &T {
assert!(index < self.len());
unsafe { mem::transmute(self.repr().data.offset(index as int)) }
}
By having `unsafe {}` it's possible to build low-level functionality as libraries rather than in the compiler. There no reason to think that code such as this would be less prone to bugs if it were hard-coded into the compiler. I'd be more inclined to believe the opposite.To be black boxes? Yes, they seem to have a long history of being that.
If I want to implement a stack data type being backed by an array, and I can not be sure that bounds checking is optimized away, I want to be able to turn off bounds checking if I'm 100% sure that my implementation indexes into the array in a correct way. I have all the information that I need about indexing into the array, since I don't expose indexing to whoever is using my stack. The compiler doesn't know more than me, in that sense. So why would I need compiler support - as in some graph which is a result of static analysis - in order to eliminate bounds checking?
But is everyone else 100% sure? Look at that CERT advisory I posted from Microsoft. "SafeBufferResize" - wasn't. Somebody at Microsoft was probably "100% sure".
If a buffer overflow in your code meant being fired, would you turn off subscript checking?
If I could get fired for my implementation not being efficient enough (and the performance hit from the bounds checking mattered as shown through benchmarking, yadda yadda), then yes. :)
How does Rust get an efficient vector type? How does it spawn a thread? How does it print something, or write something to file?
All of these need really low-level code e.g. for interacting with the operating system APIs, or handling possibly-uninitialised data.
Rust explicitly segregates `unsafe`, and we try to instil a strong aversion to using it exactly because it is dangerous and very easy to get wrong, but it's just not reasonable to remove that ability.