Remix.run Logo
dataflow 7 hours 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?

StellarScience 6 hours ago | parent | next [-]

> 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 6 hours ago | parent | prev | next [-]

That 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.

AlotOfReading 6 hours ago | parent | prev | next [-]

I 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 6 hours ago | parent | next [-]

> 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 4 hours ago | parent [-]

Thinking of it as a "stopping condition" is backwards, that part of the loop is called the 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 2 hours ago | parent [-]

> 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 6 hours ago | parent | prev [-]

> 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 3 hours ago | parent [-]

It works perfectly fine for size = 0?

theokrueger 7 hours ago | parent | prev [-]

[dead]