7 ms·
> for (size_t i = size - 1; i < size; i--) Erm... just because you can, doesn't mean you should. Also, what if you want to go down to something other than 0?
by dataflow 2mo ago
> for (size_t i = size - 1; i < size; i--)
Erm... just because you can, doesn't mean you should.
Also, what if you want to go down to something other than 0?
- theokrueger 2mo ago[dead]
- AlotOfReading 2mo agoI really don't see what's supposedly awful about that loop, but if you want to count down to x instead of 0 you just do: for (size_t i = size - 1; i >= x; i--)
- dataflow 2mo ago> I really don't see what's supposedly awful about that loop The stopping condition is incredibly confusing and non-obvious. Misleading at first glance, in fact. The whole thing is so unidiomatic that I don't think I've even seen it once in my life. It's a better contender for an underhanded C++ code contest than production code. > but if you want to count down to x instead of 0 you just do i >= x No you can't. That fails if x == 0. Which perfectly illustrates why using unsigned everywhere isn't so great. And I say this as someone who likes unsigned types and uses them more than average!
- wasmperson 2mo agoThinking of it as a "stopping condition" is backwards, that part of the loop is called the invariant: https://en.wikipedia.org/wiki/Loop_invariant https://en.wikipedia.org/wiki/Loop_invariant You should think of it as the condition that's true for all iterations, not a one-time event that halts the loop. The loop is short for this: for(size_t i = size - 1; 0 <= i && i < size; i--){ } Which works for both signed and unsigned numbers. It just so happens that for unsigned numbers you can omit the left-hand side of the &&, and for signed numbers you can omit the right-hand side. To support arbitrary lower bounds, you omit neither.
- dataflow 2mo ago> You should think of it as the condition that's true for all iterations, not a one-time event that halts the loop. (a) It's "a" condition that holds true for all iterations, not "the" condition. Plenty of other conditions can hold true across the iterations of any given loop too. In fact the one interesting thing about the loop invariant compared to any other conditions is the very fact that it is guaranteed to cease to hold immediately after the loop, assuming you don't break in the loop. Other conditions can still continue to hold. i.e. The stopping condition is the entire point of the loop invariant. (b) I'm well aware what a loop invariant is; I've worked on compilers. I am also a human. Humans care about when a loop starts and stops. There's nothing backwards about it, it's the most straightforward way people think of loops. And it's literally why more modern languages have introduced better syntaxes that merely spell the boundaries and/or values, and skip spelling the invariants entirely.
- StellarScience 2mo ago> I really don't see what's supposedly awful about that loop Exactly! That's precisely the problem with it. (Hint: think about your code when size = 0.)
- layer8 2mo agoIt works perfectly fine for size = 0?
- xigoi 2mo agoThey meant x = 0.
- layer8 2mo agoNot sure if they meant that, since the “awful” was referring to the original loop that had no x, but the generic solution in that case is: for (size_t i = size; i—- > x;)
- StellarScience 2mo ago[dead]
- StellarScience 2mo ago> for (size_t i = size - 1; i < size; i--) Agreed, seeing that example briefly made me consider whether this blog post was a parody. Sure, it works for this exact example, by relying on i wrapping "down" to MAX_INT on the last iteration. But how long will it take the next developer who works on the code base to figure that out? Will they figure it out before or after committing changes that break it? Or worse yet, before or after shipping code?
- nulltrace 2mo agoThat loop reads like a bug to anyone who hasn't memorized the wrapping rules. while (i-- > 0) on a signed index does the same thing.
- amavect 2mo agoPost-increment inverts to pre-decrement, but for-loops don't support proper syntax sugar for pre-decrement. for(size_t i = 0; i < size; i++){ // loop body } for(size_t i = size; i > 0;){ i--; // loop body }
- teo_zero 2mo agoPut the "--" in the condition. It's less ugly.
- amavect 2mo agoPedantically, that doesn't properly invert post-increment in the loop step. It decrements one extra time. If I need to use the loop index after the loop, then decrementing in the condition would cause problems. size_t i = size; while(i-- > 0){ // loop body, possibly break } use(i); // i wraps below 0 size_t i = size; while(i > 0){ i--; // loop body, possibly break } use(i); // i doesn't wrap Practically, i leaves the for-loop scope, so most never encounter this problem.
- IshKebab 2mo agoI was actually thinking that's kind of genius, even if it is a bit too subtle. Probably better than casting though. (Of course the best thing is real range types like in Rust.)