1

There are many discussions related to whether it is better to have only one or multiple exit points per function, but it is not clear to me which statements can be considered as exit points: only return or some other ones as well?

For example, should we consider throw and break as exit points?

Are there 2 or 3 exit points?

func(x, y) {
  // guard
  if (!x)
    throw "You have an error here!"

  if (y)
    return "foo"
  else
    return "bar"
}

Are there 1 or zero exit points?

func() {
  i = 1
  loop {
    if (i == 5)
      break
    
    show_message(i)
    i = i + 1
  }
}
user90726
  • 205
  • 2
  • 9
  • 2
    Related and might make your question obsolete: https://softwareengineering.stackexchange.com/questions/118703/where-did-the-notion-of-one-return-only-come-from# – Rik D Oct 07 '20 at 17:53
  • The question is very well founded. The single exit point is still a rule in several secure coding standards. And the question of how to handle the exception is explicitly handled in some more recent version of those. – Christophe Oct 08 '20 at 07:17
  • 2
    This rule comes from languages (like C) that require a cleanup block of code prior to a return. In languages that don't (C++ has destructors, Java and C# have finally) this rule is often poorly understood. In them return isn't the exit point. It's just a result being pushed on the stack. The exit is happening elsewhere. – candied_orange Oct 08 '20 at 08:48
  • 1
    @candied_orange the single exit point philosophy predates C and was already one of the preferred topic of the [structured programming movement](https://en.wikipedia.org/wiki/Structured_programming#Early_exit). I suspect that at that time it was more about algorithmic beauty and dogma (making the difference with the "goto-villains") rather than resource allocation problems (which btw didn't exist in Pascal or in Algol). – Christophe Oct 08 '20 at 19:23

1 Answers1

4

For a function, the exit point are all the places where the function is left:

  • return statement
  • reaching the end of the function body, if the language allows it (implicit return)
  • terminating the program, if the language allows this (e.g.exit()).
  • explicit throwing: it's exceptional, but de facto you leave the function.
  • implicit throwing: let's be clear, very often code that is not exception safe might exit a function and might leave some mess, especially if the function allocated some resources from the OS (e.g. OS mutex set, OS temporary file created but not destroyed, etc...)

But all those real exit points are not relevant, when it comes to discussing single exit point. Such discussions are about code readability, and are only about intentional exits according to the normal flow of operations. Only returns and terminations are relevant in this regard.

The exception handling follows an alternate flow excluded from the single exit point philosphy. In fact, exception handling can make exceptional cases safer and more readable, than the equivalent code without exception handling (see in this regard, the section "exception" of MISRA C++ 6-6-5,and Autosar C++14 section 6.8.4, which are both secure coding standards and exclude exceptions from the single exit point philosophy that both promote).

Christophe
  • 74,672
  • 10
  • 115
  • 187
  • _"But all those real exit points are not relevant, when it comes to discussing single exit point. Such discussions are about code readability, and are only about intentional exits according to the normal flow of operations."_ - So it seems that instead of _single exit point per function approach_ we should use slightly different term: _single **return** per function approach_. "Return" doesn't look as fancy as "exit point", but it seems it fits the meaning better. Am I right? – user90726 Oct 08 '20 at 03:10
  • 1
    The idea is very close to single return. But "exit point" is about the control flow, whereas "return" could mean the `return` statement or the return in the control flow (e.g. ambiguity of "single return" in your second example). And exit point also covers the termination which belongs to the nasty things the single exit point tries to avoid (things like `void f(){ write_temporary_confidential file(); if (complex condition) exit(); some_other _stuff(); delete_confidential_file(); }` ) – Christophe Oct 08 '20 at 07:10
  • _But "exit point" is about the control flow, whereas "return" could mean the `return` statement **or the return in the control flow**_ - Not sure what you mean here. Reaching the end of the function body? – user90726 Oct 08 '20 at 10:17
  • 1
    @jsv when you say “one return” you could mean either “one return statement” or “one return from the function can happen, whatever statement or event caused it”. see also [control flow](https://en.m.wikipedia.org/wiki/Control_flow) – Christophe Oct 08 '20 at 10:37
  • 1
    +1 for "The exception handling follows an alternate flow excluded from the single exit point philosphy.", both for mentioning exceptions and for calling it a philosophy instead of a fixed rule. – Ralf Kleberhoff Oct 08 '20 at 13:23
  • Related: https://softwareengineering.stackexchange.com/questions/189222/are-exceptions-as-control-flow-considered-a-serious-antipattern-if-so-why – user90726 Oct 10 '20 at 13:09
  • @jsv Interesting. Extreme care is however needed about this topic. I used "normal flow" to distinguish the expected flow of control and the exceptional/abnormal one. The discussion about exception as antipattern is only relevant when exception is misused as alternate flow within the expected flow of control; you´d better keep in mind that at a time, there were a lot of flamewars on this topic, biased by the fact that early exception implementations had some performance issues, which is no longer relevant. See the proven secure coding standards (e.g hyperlinks in answer+google for autosar) – Christophe Oct 10 '20 at 13:47
  • @jsv Moreover the accepted answer in this other thread completely missed the point about how exceptions can make code more secure with the appropriate techniques (e.g. RAII). Would you really compare such an uninformed opinion on the internet with secure coding standards elaborated on the base of failure analysis in highly controlled mission critical or life critical systems (e.g. healthcare, automotive, aerospace and military)? – Christophe Oct 10 '20 at 13:56
  • @Christophe Standards are more trustworthy than community posts (of course), and I haven't mean to somehow confront them each other. The only intent is to provide some additional context. By the way, though the accepted answer in the linked post refers to the [page](https://wiki.c2.com/?DontUseExceptionsForFlowControl) in Ward's Wiki (which is actually alive, so there is no need to use an archived copy), many people in wiki consider the use of exceptions inside control flow quite acceptable. – user90726 Oct 10 '20 at 15:08
  • 1
    @jsv secure coding standards are not iron rules either: they are more sound recommendations to avoid pitfalls that are frequently done. Whether standard or web contribution, we should never shutdown our own brain to make our mind ;-) I tend to agree with Ward's wiki (except for the goto comparison): "exceptions to be set up often but thrown rarely" represent well what I meant with "normal flow". His example of the search function is a good example of what not to do with exceptions: when you search for something,then,not finding it is a normal outcome. His reference to POLA is very relevant. – Christophe Oct 10 '20 at 15:28