Related Topics
General control issues: Chapter 19
Straight-line code: Chapter 14
Code with conditionals: Chapter 15
Code with loops: Chapter 16
Exception handling: Exceptions
Several control constructs exist in a hazy twilight zone somewhere between being leading-edge and being discredited and disproved—often in both places at the same time! These constructs aren't available in all languages but can be useful when used with care in those languages that do offer them.
Most languages support some means of exiting from a routine partway through the routine. The return and exit statements are control constructs that enable a program to exit from a routine at will. They cause the routine to terminate through the normal exit channel, returning control to the calling routine. The word return is used here as a generic term for return in C++ and Java, Exit Sub and Exit Function in Microsoft Visual Basic, and similar constructs. Here are guidelines for using the return statement:
Use a return when it enhances readability. In certain routines, once you know the answer, you want to return it to the calling routine immediately. If the routine is defined in such a way that it doesn't require any further cleanup once it detects an error, not returning immediately means that you have to write more code.
The following is a good example of a case in which returning from multiple places in a routine makes sense:
Other examples are less clear-cut, as the next subsection illustrates.
Use guard clauses (early returns or exits) to simplify complex error processing. Code that has to check for numerous error conditions before performing its nominal actions can result in deeply indented code and can obscure the nominal case, as shown here:
Indenting the main body of the routine inside four if statements is aesthetically ugly, especially if there's much code inside the innermost if statement. In such cases, the flow of the code is sometimes clearer if the erroneous cases are checked first, clearing the way for the nominal path through the code. Here's how that might look:
This simple code makes this technique look like a tidy solution, but production code often requires more extensive housekeeping or cleanup when an error condition is detected. Here is a more realistic example:
Example 17-4. More Realistic Visual Basic Code That Uses Guard Clauses to Clarify the Nominal Case
' set up, bailing out if errors are found
If Not file.validName() Then
errorStatus = FileError_InvalidFileName
Exit Sub
End If
If Not file.Open() Then
errorStatus = FileError_CantOpenFile
Exit Sub
End If
If Not encryptionKey.valid() Then
errorStatus = FileError_InvalidEncryptionKey
Exit Sub
End If
If Not file.Decrypt( encryptionKey ) Then
errorStatus = FileError_CantDecryptFile
Exit Sub
End If
' lots of code <-- 1
...
(1)This is the code for the nominal case.
With production-size code, the Exit Sub approach creates a noticeable amount of code before the nominal case is handled. The Exit Sub approach does avoid the deep nesting of the first example, however, and, if the code in the first example were expanded to show setting an errorStatus variable, the Exit Sub approach would do a better job of keeping related statements together. When all the dust settles, the Exit Sub approach does appear more readable and maintainable, just not by a very wide margin.
Minimize the number of returns in each routine. It's harder to understand a routine when, reading it at the bottom, you're unaware of the possibility that it returned some-where above. For that reason, use returns judiciously—only when they improve readability.
3.12.107.31