CS 3358 (Data Structures and Algorithms) by Lee S. Koh
Style-Related Questions and Answers

General Question and Answer items (related to programming assignments) that you may find useful.
NOTE: More recent questions appear first.

Question SR1

What is your opinion regarding the "function should have only one exit point" rule?



Answer SR1

By and large, I tend to agree with what Robert C. Martin ("Uncle Bob") said in his book ("Clean Code") regarding this controversial rule:


QUOTE


Some programmers follow Edsger Dijkstra's rules of structured programming. Dijkstra said that every function, and every block within a function, should have one entry and one exit. Following these rules means that there should only be one return statement in a function, no break or continue statements in a loop, and never, ever, any goto statements. While we are sympathetic to the goals and disciplines of structured programming, those rules serve little benefit when functions are very small. It is only in larger functions that such rules provide significant benefit. So if you keep your functions small, then the occasional multiple return, break, or continue statement does no harm and can sometimes even be more expressive than the single-entry, single-exit rule. On the other hand, goto only makes sense in large functions, so it should be avoided. 


END_QUOTE



As an example, I'd typically write:


bool allEven(const int a[], int used)
{
   for (int i = 0; i < used; ++i)
      if (a[i] % 2) return false;
   return true;
}

instead of (say)


bool allEven(const int a[], int used)
{
   bool oddNotFound = true;
   for (int i = 0; i < used; )
      if (a[i] % 2)
      {
         oddNotFound = false;
         i = used;
      }
      else
         ++i;
   return oddNotFound;
}



Here's a more involved example (from a past semester, involving linked list):


(multi-exit version)


bool LL2ContainsLL1(Node* head1, Node* head2) 

   if (head1 == 0) return true;  // empty list is always contained (even if 2nd list is empty) 
   if (head2 == 0) return false; // list1 can't be empty so can't be contained if list2 is empty 
   Node* copyOfHead2 = head2; 
   while (head1 != 0) 
   { 
      while (copyOfHead2 != 0) 
      { 
         if (head1->data == copyOfHead2->data) break; 
         copyOfHead2 = copyOfHead2->link; 
      } 
      if (copyOfHead2 == 0) return false; 
      head1 = head1->link; 
      copyOfHead2 = head2; 
   } 
   return true; 
}




(single-exit version)


bool LL2ContainsLL1(Node* head1, Node* head2) 

   bool answer;
   if (head1 == 0)
      answer = true;  // empty list is always contained (even if 2nd list is empty) 
   else
   {
      if (head2 == 0)
         answer = false; // list1 can't be empty so can't be contained if list2 is empty 
      else
      {
         Node* copyOfHead2 = head2; 
         answer = true;
         while (head1 != 0 && answer) 
         { 
            bool matchFound = false;
            while (copyOfHead2 != 0 && !matchFound) 
               if (head1->data == copyOfHead2->data)
                  matchFound = true; 
               else
                  copyOfHead2 = copyOfHead2->link; 
            if (!matchFound)
               answer = false; 
            else
            {
               head1 = head1->link; 
               copyOfHead2 = head2; 
            }
         } 
      }
   }
   return answer; 
}