Can you elaborate as to other ways Rust has worse performance?
Can you elaborate as to other ways Rust has worse performance?
Could've sworn I've read somewhere the Rust maintainers stated that Rust will never have a switch to disable bounds checking. Has this changed?
> Can you elaborate as to other ways Rust has worse performance?
I don't know of any other specifics, but benchmarks usually show D outperform Rust (and often enough, everything else), e.g.:
https://togototo.wordpress.com/2013/07/23/benchmarking-level...
https://mail.mozilla.org/pipermail/rust-dev/2014-March/00921...
In some cases, bounds checking doesn't make sense, e.g. in video games running on consoles.
As if it couldn't be used to exploit and pirate the games, get extra lifes, buy in-game items without paying, automate bots...
"Many years later we asked our customers whether they wished us to provide an option to switch off these checks in the interests of efficiency on production runs. Unanimously, they urged us not to--they already knew how frequently subscript errors occur on production runs where failure to detect them could be disastrous. I note with fear and horror that even in 1980, language designers and users have not learned this lesson. In any respectable branch of engineering, failure to observe such elementary precautions would have long been against the law."
- C.A.R Hoare Turing Award speech, 1980
> automate bots...
This has nothing to do with memory safety.
That is the key issue, "given a choice".
I saw game developers being dragged into accepting C was replacing their beautiful Assembly, followed by game developers being dragged into accepting C++ was replacing their beautiful C.
You can be pretty sure if tomorrow Sony, Apple, Nintendo, Google or Microsoft said "you must use language X", they would do it.
So yeah, given the choice they can continue to lose money thanks to memory corruption exploits.
Signed code and NX don't protect against memory corruption. One can use ROP to work around it.
Of all the languages used to implement desktop and server software (these days, at least), C is pretty much unique in that it makes no effort whatsoever to help the programmer avoid or uncover these errors.
And don't get me wrong, I pretty much like C, even though I do not use it very often, but if there was one thing I could change about it, it is this. Given the amount of bugs that stem from this property of the language, I guess I am not alone. ;-)
Not having a switch to disable bounds checking is not the same as not being able to disable bounds checking.
> I don't know of any other specifics, but benchmarks usually show D outperform Rust (and often enough, everything else), e.g.:
It's been years since I saw those benchmarks. Those are benchmarks of the built-in library random number generator. Rust uses a more secure random number generator by default than most of the other languages, so it will go slower. If you really want to benchmark random number generation, pick a faster but less secure algorithm.
Not sure what you're getting at. Marking the entire program as unsafe is not realistic. Marking specific portions leaves a long tail of code that "rarely" runs, but still adds up.
> Those are benchmarks of the built-in library random number generator.
The levgen-benchmarks programs implement the XOR-shift RNG in both the Rust and D versions.
No, it doesn't. Bounds checks in cold code don't matter (and there aren't many to begin with). Even bounds checks in hot code frequently don't matter. Have you profiled Rust code and found bounds checks to be a problem?
> The levgen-benchmarks programs implement the XOR-shift RNG in both the Rust and D versions.
Oh, I see that they changed it. Still, that benchmark is from 2013 and doesn't compile anymore. It predates unboxed closures and many other performance improvements. And 15% is in the "different register allocation decisions will affect the outcome" range, where comparisons are fairly meaningless. The fact that D and Rust beat C doesn't mean that they're faster than C.
I've measured some D code yesterday and it was like you said, bounds check didn't change performance which was very suprising (this was for JPEG loading).
In reply to https://news.ycombinator.com/item?id=10139287 :
> No, it doesn't. Bounds checks in cold code don't matter (and there aren't many to begin with).
OK, I trust your expertise on this. The "long tail" applies to optimizations in general. I don't know why the benchmarks are slower for Rust then, could be the difference in backends.
> The fact that D and Rust beat C doesn't mean that they're faster than C.
I don't know what's going on there, but some languages allow writing fast code easier than in C, e.g. SIMD vector array operations.
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)
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
});