Is there a limit to the number of nested 'for' loops?
Since everything has a limit, I was wondering if there is a limit to the number of nested for
loops or as long as I have memory, I can add them, can the Visual Studio compiler create such a program?
Of course a 64 or more nested for
loops would be not handy to debug, but is it doable?
private void TestForLoop()
{
for (int a = 0; a < 4; a++)
{
for (int b = 0; b < 56; b++)
{
for (int c = 0; c < 196; c++)
{
//etc....
}
}
}
}
Solution 1:
I'm going out on a limb by posting this, but I think that the answer is:
Between 550 and 575
with default settings in Visual Studio 2015
I created a small program that generates nested for
loops...
for (int i0=0; i0<10; i0++)
{
for (int i1=0; i1<10; i1++)
{
...
...
for (int i573=0; i573<10; i573++)
{
for (int i574=0; i574<10; i574++)
{
Console.WriteLine(i574);
}
}
...
...
}
}
For 500 nested loops, the program can still be compiled. With 575 loops, the compiler bails out:
Warning AD0001 Analyzer 'Microsoft.CodeAnalysis.CSharp.Diagnostics.SimplifyTypeNames.CSharpSimplifyTypeNamesDiagnosticAnalyzer' threw an exception of type 'System.InsufficientExecutionStackException' with message 'Insufficient stack to continue executing the program safely. This can happen from having too many functions on the call stack or function on the stack using too much stack space.'.
with the underlying compiler message
error CS8078: An expression is too long or complex to compile
Of course, this is a purely hypothetical result. If the innermost loop does more than a Console.WriteLine
, then fewer nested loops may be possible before the stack size is exceeded. Also, this may not be a strictly technical limit, in the sense that there may be hidden settings to increase the maximum stack size for the "Analyzer" that is mentioned in the error message, or (if necessary) for the resulting executable. This part of the answer, however, is left to the people who know C# in depth.
Update
In response to the question in the comments :
I would be interested to see this answer expanded to "prove" experimentally whether you can put 575 local variables on the stack if they're not used in for-loops, and/or whether you can put 575 non-nested for-loops in a single function
For both cases, the answer is: Yes, it is possible. When filling the method with 575 auto-generated statements
int i0=0;
Console.WriteLine(i0);
int i1=0;
Console.WriteLine(i1);
...
int i574=0;
Console.WriteLine(i574);
it can still be compiled. Everything else would have surprised me. The stack size that is required for the int
variables is just 2.3 KB. But I was curious, and in order to test for further limits, I increased this number. Eventually, it did not compile, causing the error
error CS0204: Only 65534 locals, including those generated by the compiler, are allowed
which is an interesting point, but has already been observed elsewhere: Maximum number of variables in method
Similarly, 575 non-nested for
-loops, as in
for (int i0=0; i0<10; i0++)
{
Console.WriteLine(i0);
}
for (int i1=0; i1<10; i1++)
{
Console.WriteLine(i1);
}
...
for (int i574=0; i574<10; i574++)
{
Console.WriteLine(i574);
}
can be compiled as well. Here, I also tried to find the limit, and created more of these loops. Particularly, I wasn't sure whether the loop variables in this case also count als "locals", because they are in their own { block }
. But still, more than 65534 is not possible. Finally, I added a test consisting of 40000 loops of the pattern
for (int i39999 = 0; i39999 < 10; i39999++)
{
int j = 0;
Console.WriteLine(j + i39999);
}
that contained an additional variable in the loop, but these seem to count as "locals" as well, and it was not possible to compile this.
So to summarize: The limit of ~550 is indeed caused by the nesting depth of the loops. This also was indicated by the error message
error CS8078: An expression is too long or complex to compile
The documentation of error CS1647 unfortunately (but understandably) does not specify a "measurement" of complexity, but only gives the pragmatic advice
There was a stack overflow in the compiler processing your code. To resolve this error, simplify your code.
To emphasize this again: For the particular case of deeply nested for
-loops, all this is rather academic and hypothetical. But websearching for the error message of CS1647 reveals several cases where this error appeared for code that was most likely not intentionally complex, but created in realistic scenarios.
Solution 2:
There is no hard limit in the C# language specification or the CLR. Your code would be iterative, rather than recursive, which could lead to a stack overflow quite fast.
There are a few things that could count as a threshold, for example the (generally) int
counter you would use, which would allocate an int
in memory for each loop (and before you have allocated your entire stack with ints...). Note that the use of that int
is required and you may reuse the same variable.
As pointed out by Marco, the current threshold is more in the compiler than in the actual language specification or runtime. Once that is recoded, you might up with quite some more iterations. If you for example use Ideone, which by default uses the old compiler, you can get over 1200 for
loops easily.
That much for loops are an indicator of bad design though. I hope this question is purely hypothetical.