Why does rust have [ ] indexing?

This is a serious bikeshedding discussion.

I have thought for some decades now that it would be great if all out of bounds indexing would immediately cause the programs to die. That is a serious, unrecoverable bug, die early is appropriate. My thought was always that there should be no performance hit for this out of bound checking, it can be built into the processor hardware.

Similarly integer overflows should cause an immediate termination. Better to die than limp along with an incorrect result.

It seems though that this is a failure of hardware support. Apparently it is OK to use billions of transistors to squeeze out performance but accelerating the detection of incorrect program behavior in hardware has not been on the agenda. Until recently perhaps with the growing awareness of security problems due to software bugs.

So our languages have to live with that and work around that hardware omission.

2 Likes

There are times when integer overflow is exactly what you want, thus the existence of the wrapping and saturation functions in Rust.

1 Like

You're in luck! Consumer ARM64 processors have started shipping support for hardware-assisted tagged pointers that can detect things like out-of-bounds array access or use-after-free.

3 Likes

No. There are never times when I want integer arithmetic to overflow. I want integer arithmetic to follow the usual rules of integer arithmetic.

When I add an integer "A" to an integer "B" I want a correct integer result "C".

If that is not possible I want a catastrophic failure. I have ordered the impossible as surely as a divide by zero.

If one want's modular arithmetic or saturating arithmetic then there should be different types to do that for you.

As I said, our hardware does not support these simple things well, so we pay the price in software, in our language design, all up the software stack. Either in the potential for unexpected error or a huge performance hit on checking results all the time.

Rust's [] indexing is different from C++'s, in that the former performs bounds checking and (safely) panics in case of failure, whereas calling the latter with an invalid index invokes undefined behavior.

Rust does provide a function, get_unchecked, similar to C++'s []. I would avoid it except after extensive measuring though, as the cost of introducing unsafe in otherwise safe code hardly compensates for the (often nonexistent, due to optimization) benefit of performance.

In general, if there has to be a trade-off between

  • guaranteed safety, potential sub-optimal performance; and

  • guaranteed optimal performance, potential safety;

personally, I would like to choose the former as the default, and only switch to the latter when absolutely necessary. Correctness is more often the focus than (the last bit of) performance.

Anytime you're writing software to emulate any piece of tech from the beginning of time until the present day, integer overflow is an ...ahem... integral part of that.

I'd rather have Rust's separate methods for overflowing, saturating, and wrapping calls than entirely separate types. There are times I need all of the above and needing type conversions for all of them would be annoying and verbose.

Sure, hardware acceleration is always great if you can get it, but I think Rust does a great job here.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.