4

Inspired from this answer of question
Is empty case of switch in C# combined with the next non-empty one?

The only occurence of this terminology is appeared in §6.5 of C# Language Specification

  • If D has a non-void return type and the body of F is a statement block, when each parameter of F is given the type of the corresponding parameter in D, the body of F is a valid statement block (wrt §8.2) with a non-reachable end point in which each return statement specifies an expression that is implicitly convertible to the return type of D.

Latter in the specification we can see

  • 8.1 End points and reachability

    Every statement has an end point. In intuitive terms, the end point of a statement is the location that immediately follows the statement. The execution rules for composite statements (statements that contain embedded statements) specify the action that is taken when control reaches the end point of an embedded statement. For example, when control reaches the end point of a statement in a block, control is transferred to the next statement in the block.
    ...

And we might have some sense of it. However, I googled and found there's no a directly explanation of non-reachable endpoint. Because Stack Overflow is a Q&A site, I would think if there is a simpler and more intuitive explanation, can easily be searched and understand of this terminology would be helpful for programmers especially who are not native English speakers.

Community
  • 1
  • 1
Ken Kin
  • 4,503
  • 3
  • 38
  • 76

2 Answers2

2

Ben's answer gives a good sense of it. To be a bit more precise, the end points of:

  • break
  • continue
  • goto
  • return
  • throw

statements are not reachable. Each one of those statements transfers control somewhere else "before it ends", so the "end point" of the statement is never hit. Compare that to statements like:

  • Console.WriteLine();
  • i++;

and so on, which transfer control to the next statement.

Loops present an interesting challenge:

while(x) { M(); }

that is essentially the same as:

BEGIN: 
if (!x) goto END;
{ M(); }
goto BEGIN;
END: ;

So the endpoint is reachable. But

while(true) { M(); }

can be optimized to:

BEGIN: 
{ M(); }
goto BEGIN;

Since there is no way to "get to the end" now, this statement is considered to have an unreachable end point. Either this loops forever, or M() never returns, or M() throws; either way, the end point of the statement is never reached.

The exact rules for determining reachability are a bit more complicated than this sketch, but that gives you a sense of them. (A challenge I like to give people to see if they have a grasp of reachability is: write a program which has a reachable goto statement but the corresponding labelled statement is unreachable. Tricky!)

These rules are used in a number of places. Three that immediately come to mind: First, a switch section must NOT have a reachable end point. Second, a method (or lambda, or property getter, etc) that is non-void must not have a reachable end point. Third, if a method has a reachable end point and it has an out parameter, the parameter must be definitely assigned at the end point.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    If the goto is reachable in that case then the labelled statement is also reachable. The challenge is to come up with a reachable goto where the label it targets is not reachable. – Eric Lippert Mar 03 '13 at 16:03
0

In simple terms, an endpoint is reached if and only if a statement completes without executing a branch (transfer of control).

So an unreachable endpoint exists for a block when a branch exiting the block is either

  1. unconditional, or
  2. exists along all possible execution paths.
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720