Programming Style Guide
It has been said that `programs must be written for people to read, and only
incidentally for machines to execute' (ref. H. Abelson and G. J. Sussman,
Structure and Interpretation of Computer Programs, MIT Press, preface to
the first edition). Therefore, as discussed in class, it is important to
follow some basic guidelines for writing source code. Follow the guidelines
below for all programming assignments. Note: We will evolve this set of
guidelines as we learn new programming paradigms, languages, and
constructs.
Remember, assignments provide you with an opportunity to show us that you care
enough to submit a professionally-prepared submission. Practice good
programming habits early and you will be rewarded with effective and efficient
programs. Following this guide will improve the readability, writeabiliy, and
maintainability of your programs and therefore reduce the likelihood of costly
errors which will save you time in debugging. A portion of your grade for all
work will be evaluated for style.
- Begin each source file with the following header filled-in appropriately.
/*******************************************************************************
/
/ filename: wc.c
/
/ description: Implements the word count command.
/
/ author: Linus Lowgator
/ login id: cps444-n1.19
/
/ class: CPS 444
/ instructor: Perugini
/ assignment: Homework #1
/
/ assigned: August 23, 2005
/ due: August 30, 2005
/
/******************************************************************************/
Shell Programming:
#*******************************************************************************
#
# filename: crossref
#
# description: A Korn shell script which cross-references C/C++ source files
# with their include files.
#
# author: Linus Lowgator
# login id: cps444-n1.19
#
# class: CPS 444
# instructor: Perugini
# assignment: Homework #2
#
# assigned: September 22, 2005
# due: October 13, 2005
#
#*******************************************************************************
Lex and Yacc:
Note:
Put your flowerbox in the definitions section of your
Lex and Yacc specification files, i.e., before
the first %%.
/*******************************************************************************
/
/ filename: calc.y
/
/ description: Yacc specification for an arithmetic calculator.
/
/ author: Linus Lowgator
/ login id: cps444-n1.19
/
/ class: CPS 444
/ instructor: Perugini
/ assignment: Homework #4
/
/ assigned: October 25, 2005
/ due: November 8, 2005
/
/******************************************************************************/
ML:
(*******************************************************************************
(
( filename: hw5.sml
(
( description: A collection of functions solving problems from Homework #5.
(
( author: Linus Lowgator
( login id: cps444-n1.19
(
( class: CPS 444
( instructor: Perugini
( assignment: Homework #5
(
( assigned: November 8, 2005
( due: November 15, 2005
(
******************************************************************************)
Do not allow any line of code to exceed 80 characters in length. Most
text editors have an option to give you column position.
Find an
appropriate place to break long program statements to continue them on the
following line. Break long character strings using string concatenation.
Indent all code within a block.
Do not use tabs anywhere in your code. For each level of
indentation, use three
spaces. Tabs cause different amounts of horizontal spacing on different
systems. By using spaces (and a fixed-width font), you guarantee your code
will be properly indented for every system, editor, and printout.
Align corresponding opening and closing braces, begin or
ends, or any other program unit delimiters. My preference for curly
braces { } (or similar delimiters)
is to always place the opening brace on the same line as
the block it opens. This makes it easy to see where blocks of code, such as
loops, begin and end, and does not waste a line of code.
An alternate style is to place each brace on line by
itself. You may use either of these styles, but do not mix them. Always be
consistent.
Use descriptive (variable, constant, procedure, function)
identifiers and use appropriate naming conventions for
variables (total_sold) and constants (OUNCES_PER_TON).
Remember, syntax should imply semantics.
- Descriptive: int dollars, average, weight
- Cryptic: int x, y, z
Initialize variables (to a value of the appropriate type) before you use them
to avoid garbage. This can be done when you declare the variable or with
an assignment statement before the variable is used.
- Incorrect: double radius = 3;
- Correct: double radius = 3.0;
Avoid type mismatches.
Do not assign a variable or literal of one type to a variable of
another, even if our compilers/interpreters permit it. Following this guideline
will make your programs portable.
- Consider: double avg_score = 76.7; int exam1 = 86;
- Incorrect: avg_score = exam1;
- Correct: avg_score = static_cast (exam1);
- Consider: double average = 0.0; int total = 967, num_students = 10;
- Incorrect: average = total/num_students;
- Correct: average = static_cast (total)/num_students;
Do not use goto.
Avoid the use of global variables.
Use comments to explain critical subsections or any ambiguous
parts of your programs (e.g., a tricky expression).
If supported, do not use multi-line comments where they
are likely to make your program less readable.
Use named constants rather than "magic" numbers. This gives you a
single point of modification which will save you time and reduce bugs.
#define SIZE 76
const int NUMBER_OF_RECORDS = 101;
const char A = 'a';
const char E = 'e';
const char I = 'i';
const char O = 'o';
const char U = 'u';
switch (character) {
case A:
case E:
case I:
case O:
case U:
}
Always use enumerated types where they make your code
more readable.
typedef enum { JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC } months;
main() {
months my_months;
switch (my_months) {
case JAN:
...
break;
case FEB:
...
break;
...
case NOV:
...
break;
case DEC:
...
break;
}
}
Enforce the principle of least privilege.
Do not use local variables with same name in different scopes
(they are different variables).
Always exit from main
with a 0 exit status to indicate success and a
non-zero status to indicate failure. Use exit
rather than return to make your program more
uniform. Use an int as
a return type for main.
int main() {
FILE* fp = NULL;
char* filename = "input.txt";
if ((fp = fopen (filename, "r")) == NULL) {
fprintf (stderr, "cannot open %s\n", filename);
exit (1);
} else {
...
exit (0);
}
Always initialize pointer variables.
Student* student_ptr = NULL;
char* filename = "input.txt";
FILE* myinstream = fopen (filename, "r");
When allocating memory, always verify that the memory was allocated successfully.
if ((student_ptr = malloc (sizeof (Student))) == NULL) {
fprintf (stderr, "out of memory!");
exit (1);
} else {
...
exit (0);
}
Once finished, always free memory that you explicitly allocated.
if ((student_ptr = malloc (sizeof (Student))) == NULL) {
fprintf (stderr, "out of memory!");
exit (1);
} else {
...
free (student_ptr);
exit (0);
}
When opening a file, always verify that the file was opened successfully.
if ((fp = fopen (filename, "r")) == NULL) {
fprintf (stderr, "cannot open %s\n", filename);
exit (1);
} else {
...
exit (0);
}
Always close files that you explicitly opened.
if ((fp = fopen (filename, "r")) == NULL) {
fprintf (stderr, "cannot open %s\n", filename);
exit (1);
} else {
...
fclose (fp);
exit (0);
}
Always print error messages to stderr.
if ((fp = fopen (filename, "r")) == NULL) {
fprintf (stderr, "cannot open %s\n", filename);
exit (1);
} else {
...
}
Routines/subprograms:
- Always use a procedure/function prototype.
- Use parameter names in procedure/function prototypes.
- Use different identifiers for formal parameters and actual parameters
to reinforce that they are different variables.
- Precede every procedure/function with the following header
explaining its purpose, the meaning of each parameter, precondition,
postcondition,
and the general
strategy of its implementation, if applicable.
/*******************************************************************************
/
/ purpose: To compute the factorial of a non-negative integer.
/
/******************************************************************************/
int factorial (int n) {
if (n == 0) then
return 1;
else
return n*factorial (n-1);
}
ML:
(*******************************************************************************
(
( purpose: To compute the factorial of a non-negative integer.
(
******************************************************************************)
fun factorial (int n): integer; begin
if (n = 0) then
factorial := 1
else
factorial := n* factorial (n-1);
end;
No routine/subprogram, block, procedure, function, or method (or message)
should exceed 50 lines of code.
Be consistent in your application of the above guidelines.
Overall, write your programs such that they are self-documenting.
In other words, structure your code such that the program itself provides
its own documentation. Self-documentation means using
descriptive identifiers and a consistent, aligned format.
Specific for Shell Programming:
- Always begin your script with a proper "bang" line.
#!/bin/ksh
Always return from your script
with a 0 exit status to indicate success and a
non-zero status to indicate failure.
Specific for Functional Programming in ML:
- Utilize recursion, higher-order functions, pattern matching,
and dynamic dispatch to the fullest extent.
- Avoid the of use imperative features other than the language's facilities for
input and output.
- Avoid statement blocks.
Use let's instead as they do not
run contrary to the spirit of functional programming.
For more information, see pp. 106--107 of [EMPL] J. D. Ullman.
Elements of ML Programming. Prentice Hall, ML97 edition, 1998.
- Avoid the use of iteration.
- Avoid side-effects, again, with the exception of
input and output.
- When possible, always use the cons operator (::) rather
than the concatenation (@) operator. "It may not be
obvious, but while it takes time proportional to the length
of the first list to concatenate lists, we can cons a head and tail in constant
time" [EMLP]. For the details, see pp. 84--88 of [EMPL].
- Never open structures.
- Verify, with your instructor, the permission to use any language feature not discussed in class by your instructor.
|