The opposite is often the case, as the architecture may not support offsetting a pointer by those sizes, requiring lots of casting in tight loops. Making that explicit makes the programmer aware of this.
This is one major reason that C compiler developers want all overflow to be undefined behavior, as it allows them to upgrade for loops that use smaller index types to larger ones.
The benefit being you can store much smaller structures, plus in the case of memory unsafety you reduce attacker control.
The vast majority of strings I personally use are certainly well under 2^32 bytes, and most are probably under 2^8.
v[i(my_u8_index)]
This could be implemented as a compile-time check, with no runtime errors. You'd have to limit which types you support as indices if you want to be portable to platforms with tiny pointers, of course.I guess something like this might be useful inside of specialized library code that worked with lots of small vectors.
But in general, Rust heavily favors explicit over implicit in many areas. If you want lots of automatic implicit behavior, something like Scala might be a better choice?
If I have an array representing a single-byte lookup table, it would be nice if I could say that the array's type is array-indexed-by-u8 rather than array-indexed-by-usize.
Ada did this well: it even lets you declare an array whose index is some enumerated type.
You can do this in Rust also: make a custom newtype wrapper for your array, and impl Index<CustomEnum> for the wrapped array.
One could argue that this is beautiful in its own way. There’s a clarity and power in being explicit while the constraints let you move on with confidence.
We want to be able to index with integer types that are smaller than or has the same size as usize, but not with integer types that are larger than usize. And we want those checks at compile time.