Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any basis for this alternative 'for' loop syntax?

Tags:

c++

for-loop

I came across a set of slides for a rant talk on C++. There were some interesting tidbits here and there, but slide 8 stood out to me. Its contents were, approximately:

Ever-changing styles

Old and busted:

for (int i = 0; i < n; i++) 

New hotness:

for (int i(0); i != n; ++i) 

I'd never seen a for loop using the second form before, so the claim that it was the "New hotness" interested me. I can see some rationale for it:

  1. Direct initialization using a constructor vs copy initialization
  2. != could be faster in hardware than <
  3. ++i doesn't require the compiler to keep the old value of i around, which is what i++ would do.

I'd imagine that this is premature optimization, though, as modern optimizing compilers would compile the two down to the same instructions; if anything, the latter is worse because it isn't a "normal" for loop. Using != instead of < is also suspicious to me, because it makes the loop semantically different than the original version, and can lead to some rare, but interesting, bugs.

Was there any point where the "New hotness" version of the for loop was popular? Is there any reason to use that version these days (2016+), e.g. unusual loop variable types?

like image 221
awksp Avatar asked Sep 14 '16 15:09

awksp


People also ask

What can I use instead of a for loop?

Array. filter, map, some have the same performance as forEach. These are all marginally slower than for/while loop. Unless you are working on performance-critical functionalities, it should be fine using the above methods.

What is the basic syntax of for loop?

Syntax of a For LoopThe for loop starts with a for statement followed by a set of parameters inside the parenthesis. The for statement is in lower case. Please note that this is case sensitive, which means the for command always has to be in lower case in C programming language.

What is the correct syntax to write a for loop?

Syntax. The init step is executed first, and only once. This step allows you to declare and initialize any loop control variables. You are not required to put a statement here, as long as a semicolon appears.


2 Answers

  1. Direct initialization using a constructor vs copy initialization

    These are exactly identical for ints and will generate identical code. Use whichever one you prefer to read or what your code policies are, etc.

  2. != could be faster in hardware than <

    The generated code won't actually be i < n vs i != n, it'll be like i - n < 0 vs i - n == 0. That is, you'll get a jle in the first case and a je in the second case. All the jcc instructions have identical performance (see instruction set reference and optionization reference, which just list all the jcc instructions together as having throughput 0.5).

    Which is better? For ints, probably doesn't matter performance-wise.

    Strictly safer to do < in case you want to skip elements in the middle, since then you don't have to worry about ending up with an infinite/undefined loop. But just write the condition that makes the most sense to write with the loop that you're writing. Also take a look at dasblinkenlight's answer.

  3. ++i doesn't require the compiler to keep the old value of i around, which is what i++ would do.

    Yeah that's nonsense. If your compiler can't tell that you don't need the old value and just rewrite the i++ to ++i, then get a new compiler. Those definitely will compile to the same code with identical performance.

    That said, it's a good guideline to just use the right thing. You want to increment i, so that's ++i. Only use post-increment when you need to use post-increment. Full stop.


That said, the real "new hotness" would definitely be:

for (int i : range(n)) { ... } 
like image 152
Barry Avatar answered Oct 02 '22 15:10

Barry


You are right about optimizing compilers and prefix vs. postfix ++ operator. It does not matter for an int, but it matters more when you use iterators.

The second portion of your question is more interesting:

Using != instead of < is also suspicious to me, because it makes the loop semantically different than the original version, and can lead to some rare, but interesting, bugs.

I would rephrase it as "can catch some rare, but interesting, bugs."

One simple way to argue this point was offered by Dijkstra in his book A Discipline of Programming. He pointed out that it is easier to reason about loops with stronger post-conditions than it is to reason about loops with weaker post-conditions. Since post-condition of a loop is the inverse of its continuation condition, one should prefer loops with weaker continuation conditions.

a != b is weaker than a < b, because a < b implies that a != b, but a != b does not imply that a < b. Therefore, a != b makes a better continuation condition.

In very simple terms, you know that a == b immediately after the loop with a != b is over; on the other hand, when the loop with a < b is over, all you know is that a >= b, which is not as good as knowing the exact equality.

like image 35
Sergey Kalinichenko Avatar answered Oct 02 '22 15:10

Sergey Kalinichenko