== Why is this an issue?

Having an infinite loop or recursion will lead to a program failure or a program never finishing the execution.

[source,csharp]
----
public int Sum()
{
    var i = 0;
    var result = 0;
    while (true) // Noncompliant: the program will never stop
    {
        result += i;
        i++;
    }
    return result;
}
----

This can happen in multiple scenarios.

=== Loop statements

`while` and `for` loops with no `break` or `return` statements that have exit conditions which are always `false` will be indefinitely executed.

=== "goto" statements

`goto` statement with nothing that stops it from being executed over and over again will prevent the program from the completion.

=== Recursion

When a https://en.wikipedia.org/wiki/Recursion_(computer_science)[recursive] method call chain lacks an exit condition, 
the https://en.wikipedia.org/wiki/Call_stack[call stack] will reach its limit and the program will crash due to a https://learn.microsoft.com/en-us/dotnet/api/system.stackoverflowexception[StackOverflowException].

[source,csharp]
----
int Pow(int num, int exponent)
{
  return num * Pow(num, exponent - 1); // Noncompliant: no condition under which Pow isn't re-called
}
----

In this example, `Pow` will keep calling `Pow` with `exponent - 1` forever, until the program crashes with a StackOverflowException.

Recursion provides some benefits.

* **Simplified code**: recursion can often lead to more concise and elegant code by breaking down complex problems into smaller, more manageable parts.
* **Improved code readability**: compared to iterative solutions, recursive solutions can be easier to understand and reason about.

However, it has disadvantages as well.

* **Stack overflow**: Recursive functions can lead to https://learn.microsoft.com/en-us/dotnet/api/system.stackoverflowexception[stack overflow] if the recursion is too deep, potentially causing the program to crash.
* **Performance overhead**: Recursive function calls can lead to poor performance due to the need to push and pop https://en.citizendium.org/wiki/Stack_frame#:~:text=In%20computer%20science%2C%20a%20stack,only%20exist%20at%20run%2Dtime[stack frames], making them potentially slower than iterative solutions.
* **Difficulty in debugging**: Debugging recursive code can be challenging, as multiple recursive calls can make it harder to track the flow of execution and identify logical errors.
* **Space complexity**: Recursive algorithms may require more memory compared to iterative approaches, as each recursive call adds a new frame to the call stack.
* **Lack of control**: Recursion can sometimes lead to infinite loops or unexpected behavior if not properly implemented or terminated, making it crucial to have proper base cases and exit conditions.

== How to fix it

The program's logic should incorporate a mechanism to break out of the control flow loop.
Here are some examples.

=== Code examples

* Use a loop condition which eventually evaluates to `false` 

==== Noncompliant code example

[source,csharp,diff-id=1,diff-type=noncompliant]
----
public int Sum()
{
    var i = 0;
    var result = 0;
    while (true) // Noncompliant: the program will never stop
    {
        result += i;
        i++;
    }
    return result;
}
----

==== Compliant solution

[source,csharp,diff-id=1,diff-type=compliant]
----
public int Sum()
{
    var i = 0;
    var result = 0;
    while (result < 1000)
    {
        result += i;
        i++;
    }
    return result;
}
----

* As S907 generally suggests, avoid using `goto` statements. Instead, you can use a loop statement or explicit recursion.

==== Noncompliant code example

[source,csharp,diff-id=2,diff-type=noncompliant]
----
public int Sum()
{
    var result = 0;
    var i = 0;
iteration: 
    // Noncompliant: program never ends
    result += i;
    i++;
    goto iteration;
    return result;
}
----

==== Compliant solution

[source,csharp,diff-id=2,diff-type=compliant]
----
public int Sum()
{
    var i = 0;
    var result = 0;
    while (result < 1000)
    {
        result += i;
        i++;
    }
    return result;
}
----

* For a recursion make sure there is a base case when the recursive method is not re-called.

==== Noncompliant code example
[source,csharp,diff-id=3,diff-type=noncompliant]
----
int Pow(int num, int exponent)
{
  return num * Pow(num, exponent - 1); // Noncompliant: no condition under which Pow isn't re-called
}
----

==== Compliant solution
[source,csharp,diff-id=3,diff-type=compliant]
----
int Pow(int num, int exponent) 
{
  if (exponent > 1) // recursion is now conditional and stoppable
  {  
    num = num * Pow(num, exponent - 1);
  }
  return num;
}
----

== Resources

=== Documentation

* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements#the-for-statement[The "for" statement]
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements#the-while-statement[The "while" statement]
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/jump-statements#the-goto-statement[The "goto" statement]
* Wikipedia https://en.wikipedia.org/wiki/Recursion_(computer_science)[Recursion - wiki]
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/api/system.stackoverflowexception?view=net-7.0[StackOverflowException class]
* S907 - "goto" statement should not be used

=== Articles & blog posts

* Edsger Dijkstra - https://www.cs.utexas.edu/users/EWD/transcriptions/EWD02xx/EWD215.html[A Case against the GO TO Statement]

ifdef::env-github,rspecator-view[]

'''
== Implementation Specification
(visible only on this page)

=== Message

Add a way to break out of this \[[method|property|property accessor]'s recursion|method|property accessor].

'''
== Comments And Links
(visible only on this page)

include::../comments-and-links.adoc[]

endif::env-github,rspecator-view[]

