Functions


Most of a software system is contained in its functions, so this is where the majority of the coding standards apply. The structure and of the function itself is just as important as the code within the function. This section includes the following topics:


Function Formatting

Precede all functions with a header comment. Use a block comment style to make it easy to visually separate one function from another.

Include the function definition immediately after the header comment. Separate the definition into:

The following example shows a sample function definition.


// *****************************************************************************
// oaPath::create()
//
// This function creates a path object in the specified cellView with the 
// specified parameters. The new path is returned in 'path'. The specified 
// point array is compressed to remove any coincident or collinear points. 
// An exception is thrown if the number of points after compression is less 
// than two.
// *****************************************************************************
void
oaPath::create(oaPath                &path,
               oaCellView            &cellView,
               oaUInt4               width,
               const oaPointArray    &points,
               oaPathStyle           style,
               oaUInt4               startExt,
               oaUInt4               stopExt)
{
    // Verify the specified cellView.
    .
    .
    .
}

Follow these guidelines when formatting a function definition.

      void oaInst::getCellName(const oaNameSpace &ns,
                               oaString          &cellName) const

Avoid Inline Function Bodies in Class Definitions

Avoid including the function body inside the class definition. Instead, place the function body outside the class definition.

The following example shows a class definition that uses an inline function body implementation.



// *****************************************************************************
// myClass
//
// 
// *****************************************************************************
class myClass {
public:
  void myFunction() {                         \\ Do not do this.
                          oaString str;        
                      
                          str.format(format, type, elements, list);      
                          cout << endl << str << endl; 
                    } 
  .
  .
  .
 
};                          

Instead, place the function body outside the class definition:


// *****************************************************************************
// myClass
//
// 
// *****************************************************************************
class myClass {
public:
  void myFunction() 
  .
  .
  .
 
};


void 
myFunction() 
{                         
    oaString str;        
                      
    str.format(format, type, elements, list);      
    cout << endl << str << endl; 
} 

Commenting Related Functions

If there are several simple functions that are related, you can use a single header comment for all the functions. In the code, separate the functions from each other with a single empty line. Use this abbreviated format only if the functions are short enough that it is still clear that the header comment refers to them all.

For example:


// *****************************************************************************
// oaPath::getWidth()
// oaPath::getStyle()
// oaPath::getStartExt()
// oaPath::getStopExt()
//
// These functions return variable attributes of this path.
// *****************************************************************************
oaUInt4
oaPath::getWidth()
{
    return oaPathData::get(index)->getWidth();
}

oaPathStyle
oaPath::getStyle()
{
    return oaPathData::get(index)->getStyle();
}

oaUInt4
oaPath::getStartExt()
{
    return oaPathData::get(index)->getStartExt();
}

oaUInt4
oaPath::getStopExt()
{
    return oaPathData::get(index)->getStopExt();
}


Aligning Variable Declarations

To improve the readability of code, variable declarations are grouped together and are formatted using tabs so that variable names align. Note that this rule does not override the rule about declaring variables in the code as late as possible. The following code shows both correct and incorrect examples of variable formatting:

// This is correct formatting, and it is easy to read.
oaString          str1("xyz");
oaUInt4           myInt = 7;
oaBlockageDataTbl *bdTbl = oaBlockageDataTbl::get(designData);
 
// This is poor formatting because it is difficult to read.
oaString str1("xyz");
oaUInt4 myInt = 7;
oaBlockageDataTbl *bdTbl = oaBlockageDataTbl::get(designData);

In some cases, many related variables are declared and initialized at the same time. In these cases, you can align both the variable name and the variable value. This formatting is somewhat subjective and is used only when the variables are related because the additional white space to align both names and values can sometimes be more difficult to read. The following example shows the correct alignment of both variable names and values.

// This is correct formatting for declaring several related variables.
oaCoord     xLoc    = 4;
oaCoord     yLoc    = 7;
oaOrient    orient  = oacR0;
oaDouble    mag     = 1.5;

Function Size

Keep functions short enough so that it is relatively easy to follow the path of execution. If a function is longer than 100 to 200 lines, consider breaking it into multiple linear parts or breaking key pieces into sub-functions.

Limit nested loops to avoid heavy indentation and very short line lengths. Instead, make some of the loops into sub-routines that can be called by the function.



Breaking Function Content into Blocks

Breaking function contents into appropriate blocks and including concise comments makes it easier for readers to get a general idea of what a function is doing without reading every line of code.

Follow these steps to make the contents of a block as clear as possible:

  1. Break the function logic into sub-blocks. For example:
  2. Write the code for each sub-block.
  3. Add a comment for each sub-block; use the comment and  two blank lines between sub-blocks to visually separate them.

The following example shows a function broken into sub-blocks.


// *****************************************************************************
// oaPath::create()
//
// This function creates a path object in the specified cellView with the 
// specified parameters. The new path is returned in 'path'. The specified point
// array is compressed to remove any coincident or collinear points. An exception 
// is thrown if the number of points after compression is less than two.
// *****************************************************************************
void
oaPath::create(oaPath                &path,
               oaCellView            &cellView, 
               oaUInt4               width,
               const oaPointArray    &points,
               oaPathStyle           style,
               oaUInt4               startExt,
               oaUInt4               stopExt)
{
    // Verify the specified cellView and the parameter types.
    oaCellViewData      *cvData = oaCellViewData::get(cellView);
    .
    .
    

    // Construct the new path object.
    oaUInt4     index = oaShapeTbl::createPath(. . .); 
    .
    .


    // Add the new path to the appropriate lppHeader.
    .
    .
    .


    // Invoke the createTrigger on the new path.
    . 
    .
    .
}

Within each sub-block of code, use one blank line between groups of related statements, and between conditional statements (if, for, while, switch, and so on) and other statements.

For example:

// *****************************************************************************
// oaNameTbl::initHashTbl()
//
// This function builds the hash table for this table. All names currently in 
// this table are added to the hash table.
// *****************************************************************************
void
oaNameTbl::initHashTbl()
{    
    oaUInt4 approxSize = numUsed << 1;    
    oaUInt4 hashSize = 32;
         
    while (hashSize < approxSize) {        
        hashSize <<= 1;    
    }                     

    hashTbl = new oaBaseNameHashTbl(*this, hashSize);     
                        
    for (oaUInt4 i = 0; i < numUsed; i++) {        
        hashTbl->add(i);    
    }
}

Nesting Classes in Functions

Nesting classes within other classes or functions, though legal, is not permitted. Generally, classes are defined in order to be used in multiple places, so putting them at a higher scoping level is appropriate and necessary. Although the nested class is hidden from the global scope, this benefit is not significant enough to mitigate the additional complexity and poor readability that the nesting technique causes. Class declarations and definitions are complex enough that they greatly obscure what it is nested within the class. Further, the number of classes created tends to be a lot fewer than the number of local variables, so the pollution of the global name space is not a factor.

Comparing Pointer and Integral Types

In general, pointers should not be explicitly compared against NULL or 0. Instead, treat them as Boolean values. For example, if someThing is a pointer type, the following code examples illustrate correct and incorrect methods for testing whether the pointer is non-NULL or NULL.

	
    // This is correct.
    if (someThing) { … 
	
    // This is incorrect.
    if (someThing != NULL)
        
    // This is correct.
    while (!someThing) { … 
	
    // This is incorrect.
    while (someThing == NULL)

Exceptions to this rule are in contexts where a value is simply being stored, passed as an argument, or being returned. For example:

    // This is correct.
    oaBoolean result = someThing != NULL;


    // This is incorrect.
    oaBoolean result = someThing;
	
    // This is correct.
    someFunctionWithABooleanParameter(someThing != NULL); 
	
    // This is incorrect. 
    someFunctionWithABooleanParameter(something);
	
    // This is correct.
    return someThing != NULL; 
    
    // This is incorrect.
    return something;
	
    // This is also correct since
    // ! produces a Boolean.
    return !someThing; 

One additional case where comparing a pointer to a NULL is legal is the use of the bit-wise operators & or | to construct Boolean expressions. It is not legal to use pointer types in such expressions, so they must be explicitly converted to Boolean:

 
    result |= something != NULL; 

Comparisons of integral types (non-pointer, non-Boolean types) to zero are always explicit. In the following examples, p->getVal() returns an oaInt4.

    // This is correct.     
    if (p->getVal() != 0) { ... 
		     
    // This is incorrrect.     
    if (p->getVal()) {... 	
	     
    // This is correct.     
    if (p->getVal() == 0) {... 
		     
    // This is incorrect.     
    if (!p->getVal()) {...  

Return to top of page