Programming Techniques II
Programming Techniques II
Programming Style
Objectives
At the end of this session, the participants will be able to follow programming style with respect to:
Naming
Expressions and statements
Consistency
Magic numbers
Writing clear code
Indenting code
Commenting
Coding Style
Naming
Naming
The naming scheme is one of the most influential aids to understanding the logical flow of an application
A name should tell "what" rather than "how"
Descriptive names emphasize on the meaning of global variables which are widely used in a program.
Naming Constants
Naming enum
Naming Variables
Since most names are constructed by concatenating several words, use mixed-case formatting to
simplify reading them.
Use Pascal casing (CalculateInvoiceTotal) for routine names where the first letter of each word is
capitalized.
For variable names, use camel casing (documentFormatType) where the first letter of each word
except the first is capitalized.
Boolean variable names should contain Is which implies Yes/No or True/False values, such as
fileIsFound.
Avoid using terms such as Flag when naming status variables, which differ from Boolean variables in
that they may have more than two possible values. Instead of documentFlag, use a more descriptive
name such as documentFormatType.
Naming Variables
Use a meaningful name even for a short-lived variable that may appear in only a few lines of code. Use
single-letter variable names such as i, or j for short-loop indexes only.
Do not use literal numbers or literal strings, such as For i = 1 To 7. Instead, use named constants, such
as For i = 1 To NUM_DAYS_IN_WEEK for ease of maintenance and understanding.
Recommendations
Be Consistent
struct UserQueue
{
int noOfItemsInQ;
int frontOfTheQueue;
int queueCapacity;
}
Observations
struct UserQueue
{
int nitems;
int front;
int capacity;
}
New structure definition is easier to understand
Structure members can be accessed in an elegant way such as:
queue.capacity++;
Users and items (structure members) in this example mean the same thing. Hence, this definition can be
improved further
New Definition
struct UserQueue
{
int nusers;
int front;
int capacity;
}
This new definition is simple and readable.
If you think that your code is sufficiently simple and readable, move ahead. Do not over-engineer it.
The names should be a concatenation of words with in principle one word to indicate the action (verb)
plus others for the objects (names). Each word is capitalized (all cases lower except the first one which
should be uppercase) but the first word is all lowercase.
e.g. setNextSubscanDocument
Avoid elusive names that are open to subjective interpretation, such as AnalyzeThis(). Such names
contribute to ambiguity more than abstraction.
In object-oriented languages, it is redundant to include class names in the name of class properties,
such as Book.BookTitle. Instead, use Book.Title.
Use the verb-noun method for naming routines that perform some operation on a given object, such as
CalculateInvoiceTotal().
In languages that permit function overloading, all overloads should perform a similar function.
If you can’t think of a good name for a function, have a deeper look at the function. The function may not
have a good purpose, or maybe it can be split into two separate functions that make code more
readable.
Be Accurate
The name of a variable or function conveys valuable information to the user. Misleading names result in
confusion and further in creating bugs.
public boolean inTable(Object obj)
{
int j = this.getIndex(obj);
return (j == NotFound)
}
What is this function doing?
Be Accurate
The function getIndex returns a value between 0 and nTable-1, if it finds the object in the table and
returns “NotFound” if it cannot.
However, when we compare that return value with “NotFound”, the check returns 1 if it succeeds. So
you have a function that returns 1 (success), when the object is not found in the table, which is
misleading.
Be Accurate
Conditional expressions that include negations are difficult to understand. Here is an example:
A typical problem may arise while handling the ternary conditional operator in C.
leap_year = y %4 == 0 && y % 100 != 0 || y % 400 == 0;
Could you notice the bug in this piece of code?
This code, in fact, does not have a bug. However, it is hard to convince yourself that the code will work.
A better practice will be to use the parentheses.
It is easy to get carried away by the rich set of operators and syntax that modern languages such as
Java, C, C++ provide. There is a tendency of cramming everything into one single statement.
Another argument that is often made in the support this tendency is code optimization.
We must remember that there is no direct relation between the size of source and the assembly or the
object code that is generated by the compiler.
Please remember that programs are primarily written for programmers and not for computers!!
Be Clear
Clarity is often achieved by writing shorter code, however a clearer code may sometimes be longer. We
must remember that the final objective is to make a programmer understand the code.
Another example,
n = (getchar() << 8) | getchar();
Now, here since the order of evaluation is undefined, second getchar() maybe invoked first.
Similarly,
arr[count] = ++count;
might assign the incremented count to wrong array element.
Indenting Code
While writing programs, pay attention to the formatting. Neatly formatted programs make them more
readable, and help you locate bugs easily.
for(n=0;n<20;arr[n++]=‘\0’);
*ptr = ‘\0’; return(‘\n’);
This confusing piece of code can easily be converted into this more readable form.
for (n = 0; n < 20; n++)
arr[n] = ‘\0’;
*ptr = ‘\0’;
return ‘\n’;
if (month == FEB) {
if (year%4 == 0)
if (day > 29)
return FALSE;
else
if (day > 28)
return FALSE;
}
This code apparently looks correct as it is well indented. However the indentation is misleading. The
problem is that a compiler will attach the “else” part to third “if” and not the second as you would have
expected.
Note
If you are maintaining a program written by someone else, please follow the style of indentation and
coding followed by the programmer who had written the program. That will keep the style of the program
consistent.
Please remember it is more important to have a consistent style rather than any particular style.
Modern programming languages will allow you to write your code in multiple ways so that all forms are
semantically equivalent. However, more standard ways would make your code more readable to you
and your colleagues.
Another advantage of using idioms is that they allow you to catch nonstandard constructs - origin of
bugs – quickly
Here are few examples on how you should write certain constructs.
Examples
if (argc == 3)
if((fin = fopen(argv[1], “r”)) != NULL)
if ((fout = fopen(argv[2], “w”)) != NULL) {
while ((c = getc(fin)) != EOF)
putc(c, fout);
fclose(fin); fclose(fout);
}
else
printf(“Can’t open output file %s\n”, argv[2]);
else
printf(“Can’t open input file %s\n”, argv[1]);
else printf(“Usage: cp inputfile outputfile\n”);
if (argc != 3)
printf(“Usage: cp inputfile outputfile”);
else if ((fin = fopen(argv[1], “r”)) == NULL)
printf(“Can’t open input file %s\n”, argv[1]);
else if ((fout = fopen(argv[2], “w”)) == NULL)
{
printf(“Can’t open output file %s\n”, argv[2]);
fclose(fin);
}
else
{
while ((c = getc(fin)) != EOF)
putc(c, fout);
fclose(fin);
fclose(fout);
}
Switch statement allows you to have a fall-through which is sometimes done intentionally to reuse the
code. At other times it is done unintentionally which gives rise to bugs.
Code with “switch” should always be written without fall-through. In case any of the statement has a fall-
through it should be clearly commented.
Example
switch (c) {
case ‘-’ :
sign = -1; // Fall-through
case ‘+’ :
c = getchar();
break;
case ‘.’ :
break;
default:
if (!isdigit(c))
return 0;
break;
}
Example
Magic numbers are literal numeric values in programs. Presence of magic numbers makes program
hard to understand and maintain.
for (j = k; j < 22; j++)
draw(j, col, star);
draw(23, 2, ‘ ‘); //label x axis;
This program can very well be converted to following program which is semantically equivalent, but
much easier to understand.
enum {
MINROW = 1, /* top edge */
MAXROW = 24; /* bottom edge (<=24)*/
MINCOL = 1; /* left edge */
MAXCOL = 80; /* right edge */
LABELROW = 1; /* position of labels */
NLET = 26; /* size of alphabet */
HEIGHT = MAXROW – 4; /* height of bars */
WIDTH = (MAXCOL – 1)/NLET /* width of bars */
};
Comments
Comments
The sole purpose of comments is to enhance the readability of code. It is important to remember that
comments are needed only at the parts of the program that are not readily understood.
Commenting should never be done mechanically.
Sloppy code combined with comments can never be a substitute for a neatly written code. Remember
that good code needs fewer comments than bad code.
Comments are often not changed as program evolves. This results into comments not in agreement with
the code.
/* Read input and write newline at the end to indicate end of current input */
For((c = getchar()) != EOF; c != EOF; i++)
str[i] = c;
Do not Confuse
if (ban_rowcount > 0)
{
/* This BAN has some future requests but they couldn't be copied to the output. Mark it as to be
procesed in the next transaction. */
SET_C_YESNOIND_NO_INDICATOR(iov_pBansBuffer->ban_buffer[indx].ban_more_rows);
SET_C_CSMREQSTS_TO_BE_PROCESSED(iov_pBansBuffer->ban_buffer[indx].ban_request_status);
if (IS_C_BOOLIND_CTRUE(moreFlag))
{
/* moreFlag indicates that despite the fact that all the BANs future requests were retrieved earlier, we
couldn't copy them to the output buffer because there was not enough space in the output buffer */
DEBUG_OL_0("moreFlag is TRUE \n");
(ov_pFutureReqBuffer->moreRows) = 1;
} /* if moreFlag */
} /* if ban_rowcount > 0 */
Commented Code
/* if (fread(&record,sizeof(record),1,in_file) != 1)*/
if (fread(&record,sizeof(record),1,in_file) != 1UL)
……;
It is quite clear from the comment that the code was altered to fix a bug. But then that gives rise to
several questions.
Why was this code commented?
Why was it not working earlier?
What made this code work now?
Is bug fixed or is it still there?
Better practice would be to delete commented code.
Summary