Chapter 17. Unusual Control Structures

cc2e.com/1778

Contents

Related Topics

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.

Multiple Returns from a Routine

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:

Multiple Returns from a Routine

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:

Example 17-1. C++ Example of a Good Multiple Return from a Routine

Comparison Compare( int value1, int value2 ) {       <-- 1
   if ( value1 < value2 ) {
      return Comparison_LessThan;
   }
   else if ( value1 > value2 ) {
      return Comparison_GreaterThan;
   }
   return Comparison_Equal;
}

(1)This routine returns a Comparison enumerated type.

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:

Example 17-2. Visual Basic Code That Obscures the Nominal Case

If file.validName() Then
   If file.Open() Then
      If encryptionKey.valid() Then
         If file.Decrypt( encryptionKey ) Then
            ' lots of code       <-- 1
            ...
         End If
      End If
   End If
End If

(1)This is the code for the nominal case.

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:

Example 17-3. Simple 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 Exit Sub
If Not file.Open() Then Exit Sub
If Not encryptionKey.valid() Then Exit Sub
If Not file.Decrypt( encryptionKey ) Then Exit Sub

' lots of code
...

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.225.235.144