descending_squares := []uint{}
for x:=4; 0<=x; x-- {
descending_squares = append(descending_squares, uint(x*x))
} descending_squares := []uint{}
for x:=4; 0<=x; x-- {
descending_squares = append(descending_squares, uint(x*x))
}See why for loops are tricky? :)
Overflows in general are tricky. How does Rust deal with it?
You can't write that check explicitly in C, but you can in assembler. Available now, across the different hardware.
(Also, I believe it introduces a lot of data dependencies, getting in the way of the out-of-order execution of modern CPUs.)
It can be the problem of the certain compilers if they don't have the infrastructure to reason about overflow flags though. But it's not a hardware problem.
In his "We Need Hardware Traps for Integer Overflow"[0], Regher quotes 5% to 100% overhead for languages such as JS or Racket, and that a "highly tuned" checker would likely be in the 5% range. Playing with arithmetics-heavy programs and Rust's checked_* (which are backed by LLVM's overflow intrinsics[1]) I got anywhere from 5 to 40% performance loss IIRC.
That's not a lot, but at the same time when you're competing with languages specifically not paying those 5%, a 5% hit on all computations is not going to get you much love.
Which is why Rust currently lets you do that (via num::Checked* and num::Saturating) but uses overflowing default semantics.
[0] http://blog.regehr.org/archives/1154
[1] http://llvm.org/docs/LangRef.html#arithmetic-with-overflow-i...
This isn't just a jump, it is a branch. Especially when the body of the loop is 6 instructions, adding an extra branch is going to be noticable.
> Also, modern compilers could optimize the checks away if they aren't used
This is equivalent to the halting problem, and most code will not be able to optimise them away. Suggesting otherwise is invoking "sufficiently smart compiler", which is invalid.
In any case, you haven't addressed the problem of missed optimisations (especially vectorisation) caused by having to maintain semantics.
> It's certainly not the problem of the CPU's.
Yes, it partly is: the data dependencies and linearisation caused by checking the CPU flags is bad.
To me golang is readable while even small rust examples don't feel quite right right.
is a completely different piece of code.
There is something that makes me uncomfortable in there:
> let descending_squares = range(0u, 5u).rev().map(|x| x * x).collect();
The overhead. I wonder about it. I am unable to get a sense of what it is. With a simple for-loop, it's rather easy to see it, but with the version above I have no idea. So "much clearer" is not what I see with the piece of code above. I see what it does, but what is not so clear is what code will be generated, something which matters when trying to write efficient code.
I wrote a blog post a while ago that used iterators heavily http://huonw.github.io/blog/2014/06/comparing-knn-in-rust/ , as you can see the performance is good.