I was converting a C++ algorithm to C#. I came across this for loop:
for (u = b.size(), v = b.back(); u--; v = p[v])
b[u] = v;
It gives no
As stated by others, the fact that C++ has implicit casting to boolean means the conditional is u--
, which will be true if the value is non-zero.
It's worth adding, that you've a false assumption in asking "where's the conditional". In both C++ and C# (and other similarly syntaxed languages) you can have an empty conditional. In this case it always evaluates to true, so the loop continues forever, or until some other condition exits it (via return
, break
, or throw
).
for(int i = 0; ; ++i)
doThisForever(i);
Indeed, any part of the for statement can be left out, in which case it's just not performed.
In general, for(A; B; C){D}
or for(A; B; C)D;
becomes:
{A}
loopBack:
if(!(B))
goto escapeLoop;
{D}
{C}
goto loopBack;
escapeLoop:
Any one or more of A, B, C or D can be left out.
As a result of this, some favour for(;;)
for infinite loops. I do because while while(true)
is more popular, I read that as "until truth ends being true", which sounds somewhat apocalyptic compared to my reading for(;;)
as "forever".
It's a matter of taste, but since I'm not the only person in the world to like for(;;)
it's worth knowing what it means.
If you're used to C / C++ this code isn't so hard to read, though it's pretty terse and not that great of code. So let me explain the parts that are more Cism than anything else. First off the general syntax of a C for loop looks like this:
for (<initialization> ; <condition>; <increment>)
{
<code...>
}
The initialization code gets run once. Then the condition gets tested before every loop and lastly the increment gets called after every loop. So in your example you'll find the condition is u--
Why does u--
work as a condition in C and not C#? Because C implicitly converts a lot of things too bools and it can cause trouble. For a number anything that is non-zero is true and zero is false. So it will count down from b.size()-1 to 0. Having the side-effect in the condition is a bit annoying and it would be preferable to put it in the increment part of the for loop, though a lot of C code does this. If I were writing it I would do it more like this:
for (u = b.size() - 1, v = b.back(); u>=0; --u)
{
b[u] = v;
v = p[v]
}
The reason for this is, to me at least, it's clearer. Each part of the for loop does it's job and nothing else. In the original code the condition was modifying the variable. The increment part was doing something that should be in the code block etc.
The comma operator may be throwing you for a loop also. In C something like x=1,y=2
looks like one statement as far as the compiler is concerned and fits into the initialization code. It just evaluates each of the parts and returns the value of the last one. So for example:
std::cout << "(1,2)=" << (1,2) << std::endl;
would print out 2.
In C everything non-zero is true
in "boolean" contexts, such as the loop end condition or a conditional statement. In C# you have to make that check explicit: u-- != 0
.
Lots of accurate answers, but I think it's worth writing out the equivalent while loop.
for (u = b.size(), v = b.back(); u--; v = p[v])
b[u] = v;
Is equivalent to:
u = b.size();
v = b.back();
while(u--) {
b[u] = v;
v = p[v];
}
You might consider refactoring to the while() format as you translate to C#. In my opinion it is clearer, less of a trap for new programmers, and equally efficient.
As others have pointed out -- but to make my answer complete -- to make it work in C# you would need to change while(u--)
to while(u-- != 0)
.
... or while(u-- >0)
just in case u starts off negative. (OK, b.size()
will never be negative -- but consider a general case where perhaps something else initialised u).
Or, to make it even clearer:
u = b.size();
v = b.back();
while(u>0) {
u--;
b[u] = v;
v = p[v];
}
It's better to be clear than to be terse.
u = b.size(), v = b.back()
is initialization.
u--
is the condition.
v = p[v]
is the iteration
The error encountered in C# itself clears the doubt. The for-loop searches for a
FALSE
condition to terminate. And as we know,
(BOOL) FALSE = (int) 0
but C# cannot process this on its own unlike as C++. So the condition you are searching for is
u--
but you have to explicitly give the condition in C# as
u-- != 0
or
u-- > 0
But still try to avoid this kind of coding practice. The
while loop
stated above in answer is one of the most simplified version of your
for-loop.