Indexed and IndexedMut traits only accept usize #29010
Closed
Description
Sample code: https://play.rust-lang.org/?gist=b9b0fad33060c74095a0&version=nightly
Short sample code that fails to compile:
let a = [0;5];
let x = a[0u8];
I'm working on a native Rust implementation of the Google Brotli compression algorithm (/~https://github.com/peter-bertok/brotli), which has a lot of low-level bit/byte twiddling and came across this issue.
- Array indexing using arbitrary integral types works in literally every other mainstream language I can think of. Many other languages allow non-integral types as well, such as their equivalent of
repr(C)
enums. - Many unnecessary explicit type casts are required in certain types of code (binary format parsing, native interop, etc...)
- An implicit cast from small unsigned integral types is never harmful. That is:
u8
,u16
, andu32
. - Casts from other types can be handled with a new warning or the existing error, with an explicit cast required to ensure the developer understands that truncation/wrapping is possible.
- Alternatively, the bounds checking in Rust can be relied upon to provide protection. E.g.: indexing with a negative value should always cause a panic. In fact, this can be made SAFER than an explicit cast. Think of the scenario where a large negative signed number is explicitly cast by the programmer to
usize
, like they have to do now. This would wrap to a small positive number, which is a valid index. If the rust compiler provides an implementation forIndexed<>
with signed types, it can insert a check for negative numbers, improving safety substantially. Currently, this compiles and runs without a panic:
let offs: i64 = -18446744073709551611;
let a = [0;50];
let x = a[offs as usize];
- This issue also causes the compiler to infer the
usize
type unexpectedly, which is confusing to developers. Goes against the rule of least surprise. This fails to compile unexpectedly:
let offs: u32 = 1; // explicit integral type. Could be a function parameter, struct member, etc...
let mut i = 0; // due to slice indexing, this is inferred to be `usize`
let a = [0;5]; // any slice of any type, doesn't matter
let x = a[i];
// This results in: "the trait `core::ops::Add<u32>` is not implemented for the type `usize`"
let y = a[i+offs];
Proposal
- Implement the
Indexed
andIndexedMut
traits foru8
,u16
, andu32
for slice and Vec types with identical behaviour to theusize
version. - Implement the
Indexed
andIndexedMut
traits forisize
,i8
,i16
, andi32
for slice and Vec types with new behaviour that panics on negative values, not just out-of-bounds positive values. - The
i64
andu64
implementations are problematic on 32-bit builds. How these are treated is up for debate.
Metadata
Assignees
Labels
No labels