3 ms·
Rust has iterators which avoid the need for direct indexing in many uses of contiguous-memory storage, and hence avoid unnecessary bounds checks (just like D's
by dbaupp 11y ago
Rust has iterators which avoid the need for direct indexing in many uses of contiguous-memory storage, and hence avoid unnecessary bounds checks (just like D's ranges). When indexing is required, bounds checking can be disabled individually by indexing with `get_unchecked` (or `get_unchecked_mut`): http://doc.rust-lang.org/std/primitive.slice.html#method.get_unchecked http://doc.rust-lang.org/std/primitive.slice.html#method.get...
In any case, when comparing language performance, it's generally good to avoid comparing backend performance, i.e. focus on the LLVM-based compilers in the pnoise benchmark. A GCC-based Rust compiler would almost certainly outperform the current LLVM-based one for that benchmark (as suggested by gcc vs. clang and gdc vs. ldc2). Of course, such a compiler doesn't currently exist, so if you care about getting your code to run as fast as possible right now, Rust isn't the best choice based on that benchmark, but Rust has several reasons that it's likely to outperform both C and D by default:
- better aliasing information (than both C and D), so compilers can optimise more aggressively
- lifetimes mean more aggressive stack allocation/ownership patterns can be used without risk (a bonus over C, and something that D solves via GC, which has its own upsides & downsides)
- the type system has been designed to be particularly good at concurrency & parallelism, so again this can be used more aggressively and in more situations (e.g. libraries can expose interfaces that allow mutating data directly on the stack of other threads without risk of data races or dangling pointers)
- aldanor 11y agoRust iterators are a bit of a crutch IMO, until it's possible to return them unboxed; if you use them heavily you end up with types one paragraph long.
- dbaupp 11y agoYeah, it's annoying that one can't return them unboxed to be easily able to construct zero-overhead lazily-evaluated sequences, but that's entirely unrelated to their avoid-bounds-checks property. Instead of iterating over a range of indices and indexing, use the slice iterator, it's basically a drop-in replacement. The former can either be done with a manual loop & addition (which is not at all lazy and definitely can't be returned, i.e. Rust's current iterators are strictly more flexible), or it is done with the Range iterator. The two lazy forms are basically the same: let v: &[T] = ...; let x: iter::Map<ops::Range<usize>, _> = (0..n).map(|i| { let elem = &v[i]; // do stuff }) let y: iter::Map<slice::Iter<T>, _> = v.iter().map(|elem| { // do stuff });