3 ms·
Rust does go overboard though, e.g. indexing requires `usize`. You either use `usize` for all your integers, or you end up with a cast-salad. arr[i as usize
by pornel 6y ago
Rust does go overboard though, e.g. indexing requires `usize`. You either use `usize` for all your integers, or you end up with a cast-salad.
arr[i as usize]
This is actually risky, because even when you only meant to extend, you can also accidentally truncate or change sign. `as` does all of these things without a warning, and mixed with type inference it can easily lead to surprises.
Rust makes it worse by insisting on a theoretical support for 16-bit and 128-bit `usize` regardless of the target platform, so you can't use `a[i.into()]` to infallibly convert `u32` to `usize` on 32-bit and 64-bit platforms.
The correct syntax is:
arr[usize::try_from(i).unwrap()]
which is painfully verbose. In larger expressions it's almost an obfuscation of what the code is actually doing.
- pjmlp 6y agoJust wait for the updated C++ standard with size_t indexers.
- joppy 6y agoThe Rust approach of having all indexing being unsigned has been extremely annoying for programming algorithms which need to do interesting indexing patterns like walking backwards through an array while indexing into another: the fact that “i >= 0” can no longer be used as a loop condition is quite exasperating. It means other more complicated indexing or looping approaches need to be used, and when showing code to coworkers (mostly mathematicians), they puzzle over this for a while before asking “why not just use i >= 0”? It’s not just this case - doing index arithmetic in general is vastly complicated by the fact that it’s difficult to detect idx < 0. I think unsignedness on array indices is one of those places where the “make invalid states unrepresentable” mantra has gone too far: yes it’s nice that theoretically the whole 64-bit index space is addressable from a byte array based at 0, but in reality -1 is just as stupid and invalid an array index as 2^64 - 1 for pretty much every use-case. What we gain is negligible; what we lose is a lot of sensible code for dealing with index arithmetic.
- jstimpfle 6y agonegative indexing could even make sense in some situations. It's not at a far stretch to imagine a pointer pointing to the one-past-last element of a series, and use e.g. -1 to get the most recent element. Python's indexing indeed works like that way.
- bbatha 6y agoAs I'm sure you're aware, this gets lost in bike shed land every time it comes up but Rust could implement `Index<iN|uN>` pretty easily. Unlike C you don't need an implicit cast to do the right thing. Personally, I have datastructure that uses non `usize` indexes I usually wrap my vector/array in in a custom type that implements index on whatever my common index types are.
- steveklabnik 6y agoIt's not only "bikeshedding", there are (in my understanding) significant inference issues that happen if we were to enable this, and that would have to be dealt with in a satisfactory way.
- piaste 6y agoI'm not a Rust programmer, but AFAIK Rust has inline functions, so if your code has lots of indexing calls, could most of the pain go away with a few short helper functions? #[inline(always)] fn idx(i : u32) { usize::try_from(i).unwrap() } or #[inline(always)] fn get(arr: [T], i : u32) { arr.[usize::try_from(i).unwrap()] } Have to repeat the definition for each numeric type you use, I guess, but hopefully you aren't using _that_ many of them.