First, as I said in another comment, Rust is great tech, written by great engineers. Puffs is still different (with different trade-offs).
And, yes, memory access patterns, cache usage, etc. affect performance.
And, yes, in general, Rust performs comparably to C/C++. As I noted elsewhere, Rust with runtime arithmetic overflow checks currently performs worse than Rust without such checks. So, yes, Rust without those checks is as fast as C, and in general, arithmetic overflow isn't the biggest concern.
steveklabnik, a Rust expert, commented on this page that, in the future, "if the runtime checks get cheap enough, we can do them in release mode as well". If so, that's great, I'm happy to be proven wrong. Cheap still isn't zero, though, and see "nanoseconds become milliseconds" at https://groups.google.com/forum/#!topic/puffslang/2z61mNTAMn...
In contrast, Puffs today performs as fast as C, with arithmetic overflow checks. They just happen to be compile time checks. And sometimes overflow is indeed a concern (search for "underflow" in https://blog.chromium.org/2012/05/tale-of-two-pwnies-part-1....).
I'm sorry, but I don't understand what you mean by bounds checks being done at the slice level and not per-element access. A statement like "pixels[y * stride + x] = etc" is per-element, right?
> I'm sorry, but I don't understand what you mean by bounds checks being done at the slice level and not per-element access. A statement like "pixels[y * stride + x] = etc" is per-element, right?
Yes, if you index a slice you have to check each access. However the idiomatic way to work with strides of data in Rust is to use Iterators.
Bounds is checked at the entry of an iteration and the the inner loop is nice and fast. So your example would be:
for pixel in &mut pixels[0..y*stride+x] {
*pixel = etc
}
I tried to do something similar on the playground[1] but it turns out Rust/LLVM is too smart and folded the whole loop down to a constant.
> In contrast, Puffs today performs as fast as C, with arithmetic overflow checks. They just happen to be compile time checks.
I'll grant that's largely true, but as far as I can see it's not entirely true. For example, to quote a comment from one of the example .puffs files:
// Set history_index (modulo 0x8000) to the length of this
// remainder. The &0x7FFF is redundant, but proves to the
// compiler that the conversion to u32 will not overflow.
In this case, the redundant operation is equivalent to a disabled arithmetic overflow check, although it's (commendably) made more explicit.
Similarly, in decode_lzw.puffs, I think (could be wrong) that some of the conditions in 'if' statements, e.g. "(width < 12)", should always be true unless the image is malformed. In a way, this is substituting for a runtime array bounds check and/or overflow check that might be hit if the condition weren't present. Here too, Puffs arguably wins by making the check explicit. If I'm right that the author stuffed in extra conditions where demanded by the compiler, rather than properly considering the consequences of their being false (e.g. should probably result in returning an error), then there's some argument that it would be better to crash than silently misbehave. But even then, at least Puffs makes the problem relatively obvious, whereas in e.g. Rust you just have to trust that your code won't perform any overflows.
Integer overflow is a huge concern in C, but much less of one in memory-safe languages, where a buffer size being miscalculated should result in a controlled panic rather than memory corruption (…at least if you're not interfacing with unsafe code). Still, an overflow is effectively a miscalculation, incorrect behavior, and with any kind of incorrect behavior there's always a chance it will compromise security in some way.
And, yes, memory access patterns, cache usage, etc. affect performance.
And, yes, in general, Rust performs comparably to C/C++. As I noted elsewhere, Rust with runtime arithmetic overflow checks currently performs worse than Rust without such checks. So, yes, Rust without those checks is as fast as C, and in general, arithmetic overflow isn't the biggest concern.
steveklabnik, a Rust expert, commented on this page that, in the future, "if the runtime checks get cheap enough, we can do them in release mode as well". If so, that's great, I'm happy to be proven wrong. Cheap still isn't zero, though, and see "nanoseconds become milliseconds" at https://groups.google.com/forum/#!topic/puffslang/2z61mNTAMn...
In contrast, Puffs today performs as fast as C, with arithmetic overflow checks. They just happen to be compile time checks. And sometimes overflow is indeed a concern (search for "underflow" in https://blog.chromium.org/2012/05/tale-of-two-pwnies-part-1....).
I'm sorry, but I don't understand what you mean by bounds checks being done at the slice level and not per-element access. A statement like "pixels[y * stride + x] = etc" is per-element, right?