SDSU CS535 Object-Oriented Programming & Design
Fall Semester, 1996
Doc 10, Comments on Assignment 1

[To Lecture Notes Index]
San Diego State University -- This page last updated Oct 1, 1996
----------

Contents of Doc 10, Comments on Assignment 1

  1. References
  2. Meyer's Criteria for Evaluating for Modularity
  3. Indentation, White space
  4. Names
  5. Comments
    1. Kinds of Comments
    2. Commenting Efficiently
    3. Commenting Techniques
    4. Commenting Data Declarations
    5. Commenting Routines
  6. Returning Flags
  7. Fields as Global Variables
  8. IO in Classes
  9. How do you implement a Queue?
  10. Queue Class
    1. Efficient grow
  11. Problem 1 String Replacement

Doc 10, Comments on Assignment 1 Slide # 1

References


Various student papers

Code Complete, Steve McConnell, Microsoft Press, 1993, chapters 9 and 19


Doc 10, Comments on Assignment 1 Slide # 2Listen Here!

Meyer's Criteria for Evaluating for Modularity


Doc 10, Comments on Assignment 1 Slide # 3Listen Here!

Indentation, White space

public class Assgn1_Part1
{
   public static void main(String args[])
   {
            Console.println();
// Initialize strings
      DataString A=new DataString('A');      // This will prompt 
===>the user for a string.
      DataString B=new DataString('B');      // This will prompt 
===>the user for a string.
      DataString C=new DataString('C');      // This will prompt 
===>the user for a string.
      String D="";
      int i=0;
      do
      {
         {
            String a;
            String b;
            int j=0;
// Check each character of A
            do
            {
               a = A.Data.substring(i+j,i+j+1);
               b = B.Data.substring(j,j+1);
               j++;
            }
// If a letter matches, see if the whole string B is contained 
            while (a.toLowerCase().equals(b.toLowerCase())
               &&(j<B.Data.length()))
            if (a.toLowerCase().equals(b.toLowerCase())
               &&(j<B.Data.length()))
            {
// Place C into D
               D=D+C.Data;
               i+=j;
            }
            else
            {
// Place the letter from A into D
               D=D+A.Data.substring(i,i+1);
               i++;
            }
         }
      }
// Do until the end of A is too short to contain B
      while (i<=(A.Data.length()-B.Data.length()));
// Place the remainder of A into D
      D=D+A.Data.substring(i,A.Data.length());
      Console.println(D+"\n");
   }
}

Doc 10, Comments on Assignment 1 Slide # 4Listen Here!
Indentation, White space

Use white space to make program readable

Use indentation to show the program structure

while (a.toLowerCase().equals(b.toLowerCase())
   &&(j<B.Data.length()))
if (a.toLowerCase().equals(b.toLowerCase())
   &&(j<B.Data.length()))
verses
while   (    ( a.toLowerCase().equals( b.toLowerCase() ) ) && 
         ( j<B.Data.length() ) 
      )
      if   (   ( a.toLowerCase().equals( b.toLowerCase() ) ) &&
            ( j<B.Data.length() )
         )
      {
         // Code deleted
      }

verses

while   (    ( a.toLowerCase().equals( b.toLowerCase() ) ) && 
         ( j<B.Data.length() ) 
      )
      {
         // Code deleted
      }


Doc 10, Comments on Assignment 1 Slide # 5Listen Here!

Names

Example 1
String A;
String B;
String C;
String D;

verses
String  strOriginal;
String  strSearch;
String  strReplace;
String  strNew;


Example 2

private  void  growQueue()  {

   temp  =  new char[ size ];

verses
private  void  growQueue()  {

   char[]  newQueueSpace = new char[ newQueueSize  ]



Doc 10, Comments on Assignment 1 Slide # 6Listen Here!
Example 3

class Buffer {
   char[]  buff;
   // I removed the rest of the class
}

in driverProgram()  {

   Buffer buffr  =  new Buffer()


verses

class CharQueue  {

   char[]  queueElements;
   // blah blah blah
}

in driverProgram()  {

   CharQueue  buffer  =  new CharQueue();


Doc 10, Comments on Assignment 1 Slide # 7Listen Here!
Names

"Finding good names is the hardest part of OO Programming"

"Names should fully and accurately describe the entity the variable represents"

What role does the variable play in the program?
Data StructureRole, function
InputRecEmployeeData
BitFlagPrinterReady
Queuebuffer

Some Examples of Names, Good and Bad
TrainVelocityVelt, V, X, Train
CurrentDateCD, Current, C, X, Date
LinesPerPageLPP, Lines, L, X

Doc 10, Comments on Assignment 1 Slide # 8Listen Here!

Comments

private int INITIAL_SIZE = 32;      // initial size of buffer


TempB = B.toLowerCase();         // get lower case of string


buffer[head] = ch;               // insert the char


x = x * 2                        // multilpy x by 2



verses
private int INITIAL_BUFFER_SIZE = 32;


TempB = B.toLowerCase();   // comparison is case insensitive
                        // compare uppercase strings


queueElements[ head ] = newQueueItem;


//  doubling queueSize results in O(1) cost per insertion
queueSize = queueSize * 2


Doc 10, Comments on Assignment 1 Slide # 9
Comments

"Comments are easier to write poorly than well, and comments can be more damaging than helpful"
What does this do?
for i := 1 to Num do
 MeetsCriteria[ i ] := True;
for  i := 1 to Num / 2  do begin
 j := i + i;
 while ( j <= Num ) do begin
  MeetsCriteria[ j ] := False;
  j := j + i;
 end;
for i := 1 to Mun do
 if MeetsCriteria[ i ] then
  writeln( i, ' meets criteria ' );



Doc 10, Comments on Assignment 1 Slide # 10
How many comments does this need?



for PrimeCandidate:= 1 to Num do
   IsPrime[ PrimeCandidate] := True;

for  Factor:= 1 to Num / 2  do begin
   FactorableNumber := Factor + Factor ;
   while ( FactorableNumber <= Num ) do begin
      IsPrime[ FactorableNumber ] := False;
      FactorableNumber := FactorableNumber + Factor ;
   end;
end;

for PrimeCandidate:= 1 to Num do
   if IsPrime[ PrimeCandidate] then
      writeln( PrimeCandidate, ' is Prime ' );



Good Programming Style is the Foundation of Well Commented Program

Doc 10, Comments on Assignment 1 Slide # 11Listen Here!

Kinds of Comments

X := X + 1    /* add one to X



/* if allocation flag is zero */

if ( AllocFlag == 0 ) ...


Used to explain complicated or tricky code
*p++->*c = a

/* first we need to increase p by one, then ..
Make code simpler before commenting
(*(p++))->*c = a



ObjectPointerPointer++;
ObjectPointer = *ObjectPointerPointer;
ObjectPointer ->*DataMemberPointer = a;
/*  **** Need to add error checking here  **** */




Distills a few lines of code into one or two sentences
Explains the purpose of a section of code
{ get current employee information }   intent


{ update EmpRec structure }     what

Doc 10, Comments on Assignment 1 Slide # 12

Commenting Efficiently

/***********************************
 * module: Print                   *
 *                                 *
 * author: Roger Whitney           *
 * date:   Sept. 10, 1995          *
 *                                 *
 * blah blah blah                  *
 *                                 *
 ***********************************/



/***********************************
  module: Print          
                         
  author: Roger Whitney  
  date:   Sept. 10, 1995 
                         
  blah blah blah         
                         
 ***********************************/



Doc 10, Comments on Assignment 1 Slide # 13Listen Here!

Commenting Techniques

Commenting Individual Lines

Avoid self-indulgent comments
MOV AX,  723h        ;    R. I. P. L. V. B.



Endline comments have problems

MemToInit := MemoryAvailable(); { get memory available }

Not much room for comment
Must work to format the comment



Use endline comments on
Data declarations
Maintenance notes
Mark ends of blocks

Doc 10, Comments on Assignment 1 Slide # 14
Commenting Paragraphs of Code

Write comments at the level of the code's intent

Comment the why rather than the how

Make every comment count

Document surprises

Avoid abbreviations
How verses Why
How
/* if allocation flag is zero */

if ( AllocFlag == 0 ) ...

Why
/* if allocating a new member */

if ( AllocFlag == 0 ) ...

Even Better
/* if allocating a new member */

if ( AllocFlag == NEW_MEMBER ) ...

Doc 10, Comments on Assignment 1 Slide # 15
Summary comment on How
{ check each character in "InputStr" until a 
  dollar sign is found or all characters have 
  been checked }

Done   := false;
MaxPos := Length( InputStr );
i      := 1;
while ( (not Done) and (i <= MaxLen) ) begin
   if ( InputStr[ i ] = '$' ) then
      Done := True
   else
      i := i + 1
end;




Doc 10, Comments on Assignment 1 Slide # 16
Summary comment on Intent
{ find the command-word terminator }

Done   := false;
MaxPos := Length( InputStr );
i      := 1;

while ( (not Done) and (i <= MaxPos ) ) begin
   if ( InputStr[ i ] = '$' ) then
      Done := True
   else
      i := i + 1
end;


Doc 10, Comments on Assignment 1 Slide # 17
Summary comment on Intent with Better Style
{ find the command-word terminator }

FoundTheEnd      := false;
MaxCommandLength := Length( InputStr );
Index            := 1;

while ((not FoundTheEnd) and 
       (Index <= MaxCommandLength)) begin

   if ( InputStr[ Index ] = '$' ) then
      FoundTheEnd := True;
   else
      Index := Index + 1;
end;

Doc 10, Comments on Assignment 1 Slide # 18

Commenting Data Declarations


Comment the units of numeric data

Comment the range of allowable numeric values

Comment coded meanings
var
   CursorX:      1..MaxCols;   { horizontal screen position of cursor }
   CursorY:      1..MaxRows;   { vertical position of cursor on screen }

   AntennaLength:   Real;   { length of antenna in meters: >= 2 }
   SignalStrength:   Integer;   { strength of signal in kilowatts: >= 1 }

   CharCode:      0..255;   { ASCII character code }
   CharAttib:      Integer;   { 0=Plain; 1=Italic; 2=Bold  }
   CharSize:         4..127;   { size of character in points }

Comment limitations on input data

Document flags to the bit level


Doc 10, Comments on Assignment 1 Slide # 19

Commenting Routines


Avoid Kitchen-Sink Routine Prologs

Keep comments close to the code they describe

Describe each routine in one or two sentences at the top of the routine

Document input and output variables where they are declared

Differentiate between input and output data

Document interface assumptions

Keep track of the routine's change history

Comment on the routine's limitation

Document the routine's global effects

Document the source of algorithms that are used
procedure InsertionSort 
   {
   Var   Data:      SortArray;    { sort array elements }
      FirstElement:   Integer        {index of first element to sort}
      LastElement:   Integer        {index of last element to sort}
   }

Doc 10, Comments on Assignment 1 Slide # 20Listen Here!

Returning Flags

public char removeChar()
{
   if ( isQueueEmpty() == true )
      return '\u0000';
   else
      return  queueElements[ queueFront-- ]
}

verses
class CharQueue  
{
   //  Select a rare unicode for remove char from empty
   //  queue flag
   public static final char EMPTY = \u0000';

   public char removeChar()
   {
      if ( isQueueEmpty() == true )
         return EMPTY ;
      else
         return  queueElements[ queueFront-- ]
   }
}

public void static main( String arg[] )
{
      blah blah blah

      char fromQueue = buffer.removeChar();
      if ( fromQueue == CharQueue.EMPTY )
         do something proper
      else
         the real code goes here

Doc 10, Comments on Assignment 1 Slide # 21Listen Here!
Issue Who checks for Empty Queue?

Options
Queue class only
User code only
Both user code and queue class
Queue Class only

Queue class can not know the proper response to removing a character from an empty queue!

This option does not work

Both User and Queue

See previous slide
Doc 10, Comments on Assignment 1 Slide # 22Listen Here!
User Code Only

User code
public void static main( String arg[] )
{
      blah blah blah

      if ( buffer.isEmpty() == false )
         fromQueue = buffer.removeChar();
      else
         error condition, handle it here

Queue code
class CharQueue  
{

   public char removeChar()
   {
      return  queueElements[ queueFront-- ]
   }

Doc 10, Comments on Assignment 1 Slide # 23Listen Here!
How to tell User to check
Documentation
   /** User must insure that the queue is not empty before calling
    *  removeChar
    * @return first character in the queue
    */
   public char removeChar()
   {
      return  queueElements[ queueFront-- ]
   }
Assert
   public char removeChar()
   {
      Assert.condition( isQueueEmpty() == false );

      return  queueElements[ queueFront-- ]
   }

C/C++ have an assert call
In Java we have to build our own

Exceptions will modify this
final class Assert {
   public static void condition( boolean  expression )
   {
      if ( expression == false )
         warn user some how
   }
}

Doc 10, Comments on Assignment 1 Slide # 24Listen Here!

Fields as Global Variables

class ThreeStrings {
   static String A, B, C, D;

   static void ReadStrings()  {
      A = Console.readLine( "Enter string A: " );
      B = Console.readLine( "Enter string B: " );
      C = Console.readLine( "Enter string C: " );
   }

   static void ReplaceStrings()  {
      // Code here to do the string replacement
      
      D = stringReplaced;
   }

   static void OutputString() {
      Console.println( "\nString D is: " + D );
   }

   public static void main( String args[] ) {
      ReadStrings();
      ReplaceStrings();
      OutputString();
   }
}

Doc 10, Comments on Assignment 1 Slide # 25Listen Here!
Remove the Globals
Now we can use the class elsewhere!
class ThreeStrings {

   static void ReadStrings( String A, String B, String C )  {
      A = Console.readLine( "Enter string A: " );
      B = Console.readLine( "Enter string B: " );
      C = Console.readLine( "Enter string C: " );
   }

   public static String ReplaceStrings( String A, 
                              String B, 
                              String C 
                              )  {
      // Code here to do the string replacement
      
      return stringReplaced;
   }

   public static void main( String args[] ) {
      String A, B, C, D;

      ReadStrings( A, B, C );
      D = ReplaceStrings( A, B, C );
      Console.println( "\nString D is: " + D );
   }
}

Doc 10, Comments on Assignment 1 Slide # 26
More Fields as Global Variables
class Queue {

   private char[] elements;
   private int queueFront;
   private int queueRear;
   private int queueCount;

   private char[]  tempQueue;


   private void growQueue()
   {
      tempQueue = new char[ elements.length * 2 ];
      
      for ( int k = 0; k < elements.length; k++ )
         tempQueue[ k ] = elements[ k ];

      elements = tempQueue;
   }   
}

Just declare tempQueue locally, not as field in class
   private void growQueue()
   {
      char[]  tempQueue;
      tempQueue = new char[ elements.length * 2 ];
      
      for ( int k = 0; k < elements.length; k++ )
         tempQueue[ k ] = elements[ k ];

      elements = tempQueue;
   }   

Doc 10, Comments on Assignment 1 Slide # 27Listen Here!
Even More Fields as Global Variables
class WrongWay  {

   private int argumentOne;      // used only in helper and
   private int argumentTwo;   // FunctionThatNeedsHelper
   
   public void  FunctionThatNeedsHelper()  {
      // do some stuff
      // need to call helper function that needs two parameters
      // so save parameters in fields

      argumentOne = blah;
      argumentTwo = moreBlah;

      // now call helper method

      result = helper();
   }

   private int helper()  {
      // now read parameters
      return argumentOne / argumentTwo + 10;
   }
}

class BetterWay  {
   public void  FunctionThatNeedsHelper()  {
      result = helper( blah, moreBlah );
   }

   private int helper(int a, int b )  {
      return a / b + 10;
   }
}

Doc 10, Comments on Assignment 1 Slide # 28Listen Here!

IO in Classes

Example 1
public void enqueue( )
{
   char  charToAdd;
   charToAdd = Console.readLine("Enter char for queue").charAt(0);

   if ( isQueueFull() == true )
      growQueue();
      
   elements[ queueRear ] = charToAdd;
   queueRear = ( queueRear + 1 ) % queueSize();
   elementCount++;
}

Example 2
public void enqueue( char  charToAdd )
{
   Console.println( "Adding char to queue " + charToAdd );

   if ( isQueueFull() == true )
      growQueue();
      
   elements[ queueRear ] = charToAdd;
   queueRear = ( queueRear + 1 ) % queueSize();
   elementCount++;
   Console.println( "queueRear  is now: " + queueRear );
}

Doc 10, Comments on Assignment 1 Slide # 29Listen Here!
Example 3
public void print() 
{
   Console.print( "Front " + queueFront );
   Console.print( " Rear " + queueRear ); 
   Console.println( " " + String.valueOf( queueElements ) );
}

Doc 10, Comments on Assignment 1 Slide # 30Listen Here!

How do you implement a Queue?



public void enqueue( char  charToAdd )
{
   char[] newQueue = new char[ queueSize() + 1];

   for ( int i = 0; i < queueSize(); i++ )
      newQueue[ i + 1 ] = queueElements[ i ];

   queueElements = newQueue;

   queueElements[ 0 ] = charToAdd;
   queueRear =  queueRear + 1;
   elementCount++;
}

Doc 10, Comments on Assignment 1 Slide # 31Listen Here!

Queue Class

class CharQueue
   {
   /* Class invariant,
    * queueRear is the location the next queue item should be placed
    * If the queue is not empty, queueFront is the location of the first
    * item in the queue
    */
    
   private char[] queueElements;
   private int queueFront;
   private int queueRear;
   private int elementCount;
      
   public static final int DEFAULT_QUEUE_SIZE = 256;
   
   
   public CharQueue( int Size )
      {
      queueElements = new char[ Size ];
      queueFront = 0;
      queueRear = 0;
      elementCount = 0;   
      }
      
   public CharQueue(  )
      {
      this( DEFAULT_QUEUE_SIZE );
      }


Doc 10, Comments on Assignment 1 Slide # 32Listen Here!
//Queue Operations

   public char dequeue( )
      {
      char itemRemoved = queueElements[ queueFront ];
      queueFront = ( queueFront + 1 ) % queueCapacity();
      elementCount--;
      return itemRemoved;
      }

   public void enqueue( char itemToAdd )
      {
      if ( isFull() == true )
         growQueue();
      
      queueElements[ queueRear] = itemToAdd;
      queueRear = ( queueRear + 1 ) % queueCapacity();
      elementCount++;
      }

   public boolean  isFull()
      {
      if ( elementCount >= queueCapacity() )
         return true;
      else
         return false;
      }

   public boolean  isEmpty()
      {
      if ( elementCount == 0 )
         return true;
      else
         return false;
      }

Doc 10, Comments on Assignment 1 Slide # 33Listen Here!
//Queue Operations
   public String toString()
      {
      return "Front " + queueFront + 
            "Rear " + queueRear + " " + 
            String.valueOf( queueElements );
      }
         
   private void growQueue()
      {
      CharQueue newQueue;
      newQueue = new CharQueue( queueCapacity() * 2 );

      while ( isEmpty() == false )
         {
         newQueue.enqueue( dequeue() );
         }
      
      queueElements = newQueue.queueElements;
      queueFront = newQueue.queueFront;
      queueRear = newQueue.queueRear;
      elementCount = newQueue.elementCount;
      }   

   private int queueCapacity()
      {
      return queueElements.length;
      }
   }



Doc 10, Comments on Assignment 1 Slide # 34
Using the Queue Class
class QueueTest 
   {
   public static void main( String[] args )
      {
      String testData = "abcdefghijklmnopqrstuvwxyz";
      int nextLetter = 0;
      CharQueue buffer = new CharQueue( 4 );

      buffer.enqueue( '1');
      buffer.enqueue( '2');
      buffer.enqueue( '3');
      for ( int k = 0; k < 3; k++ )
         {
         buffer.enqueue( testData.charAt( nextLetter++ ) );
         buffer.dequeue( );
         System.out.println( buffer );
         }

      for ( int k = 0; k < 9; k++ )
         {
         buffer.enqueue( testData.charAt( nextLetter++ ) );
         System.out.println( buffer );
         }

      for ( int k = 0; k < 8; k++ )
         {
         System.out.println( buffer.dequeue(  ) );
         }

      for ( int k = 0; k < 14; k++ )
         {
         buffer.enqueue( testData.charAt( nextLetter++ ) );
         System.out.println( buffer );
         }
      }
   }

Doc 10, Comments on Assignment 1 Slide # 35Listen Here!

Efficient grow


/*  Assumes called only when queue is full. Thus 
 *   queueFront = queueRear
 *   Use native method to copy arrays:
 *      arraycopy(src, srcPosition,dest,destPosition, length)
 *    Parameters: 
 *      src - the source data 
 *      srcpos - start position in the source data 
 *      dest - the destination 
 *      destpos - start position in the destination data 
 *      length - the number of array elements to be copied 
 */

private void growQueue()
   {
   char[] newQueue = new char[ queueCapacity() * 2 ];
   
   int elementsFromFrontToEnd = queueCapacity() - queueFront;


   System.arraycopy( queueElements, queueFront,  
                     newQueue, 0, 
                     elementsFromFrontToEnd);

   System.arraycopy( queueElements, 0,  
                  newQueue, elementsFromFrontToEnd, 
                  queueRear);

   queueElements = newQueue;
   queueFront = 0;
   queueRear = elementCount;
   }

Doc 10, Comments on Assignment 1 Slide # 36Listen Here!

Problem 1 String Replacement

class StringManipulation 
   {
   public static final int NOT_FOUND = -1; 

   private String text;
   private boolean ignoreCase = true;
   
   public StringManipulation( String textToManipulate ) 
      {
      text( textToManipulate );
      }

   public ignoreCase( boolean yesOrNo )
      {
      ignoreCase = yesOrNo;
      }

   public String toString()
      {
      return text();
      }
      
   private void text( String newText ) 
      {
      text = newText;
      }

   private String text(  ) 
      {
      return text;
      }


Doc 10, Comments on Assignment 1 Slide # 37Listen Here!
// More String
   public int indexOf( String pattern, int fromIndex ) 
      {
   
      for (    int searchIndex = fromIndex; 
            searchIndex <= text().length() - pattern.length(); 
            searchIndex ++ 
         )
         {
         boolean match;
         match = text().regionMatches( ignoreCase, searchIndex , 
                              pattern, 0, pattern.length() );
         if ( match == true )
            return index;
         }
      return NOT_FOUND;
      }

   public void replaceFirst(    String searchPattern, 
                        String replacePattern 
                         ) 
      {
      int searchIndex = indexOf( searchPattern, 0 );
      
      if ( searchIndex != NOT_FOUND )
         {
         StringBuffer newText = new StringBuffer();
         newText.append( text().substring( 0, searchIndex) );
         newText.append( replacePattern );
         newText.append( text().substring( searchIndex + 
                           searchPattern.length() ) 
                          );
         
         text( newText.toString() );
         }
      }

Doc 10, Comments on Assignment 1 Slide # 38Listen Here!
// Problem 1
   public void replaceAll(    String searchPattern, 
                        String replacePattern 
                       ) 
      {
      StringBuffer newText = new StringBuffer();

      int startIndex = 0;
      int searchIndex = indexOf( searchPattern, startIndex );
      
      while ( searchIndex != NOT_FOUND )
         {
         newText.append( text().substring( startIndex, searchIndex) );
         newText.append( replacePattern );

         startIndex = searchIndex + searchPattern.length();
         searchIndex = indexOf( searchPattern, startIndex );
         }

      newText.append( text().substring( startIndex ) );
      text( newText.toString() );
      }
   

Doc 10, Comments on Assignment 1 Slide # 39Listen Here!
// Start of Problem 3

   public String grepLikeFind(    String startPattern, 
                           String endPattern, 
                           int fromIndex 
                          ) 
      {
      int startIndex = indexOf( startPattern, fromIndex );
      
      if ( startIndex == NOT_FOUND )
         return "";
      
      int endPatternIndex;
      endPatternIndex = indexOf( endPattern, 
                             startIndex + startPattern.length() 
                            );

      if ( endPatternIndex == NOT_FOUND )
         return "";

      return text().substring( startIndex, 
                          endPatternIndex + endPattern.length() 
                        );
      }
   } // End class

Doc 10, Comments on Assignment 1 Slide # 40Listen Here!
How about Undo!
class StringManipulation 
   {
   public static final int NOT_FOUND = -1; 

   private String text;
   private boolean ignoreCase = true;
   private Stack changeHistory = new Stack();
   
   private void text( String newText ) 
      {
      changeHistory.push( text );
      text = newText;
      }

   public void undo()
      {
      text = ( String ) changeHistory.pop();
      }

// Rest of class the same

----------