4 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 3mo 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?
- nulltrace 3mo 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.
- theokrueger 3mo ago[dead]
- AlotOfReading 3mo 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 3mo 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 3mo 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 3mo 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 3mo 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 3mo agoIt works perfectly fine for size = 0?
- xigoi 3mo agoThey meant x = 0.
- layer8 3mo 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 3mo ago[dead]
- StellarScience 3mo 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?
- amavect 3mo 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 3mo agoPut the "--" in the condition. It's less ugly.
- amavect 3mo 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 3mo 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.)