Commenting
Commenting is an important part of helping others understand and use our code. On every assignment, part of your grade will be based on how well your code is commented. This page describes the commenting expectations in CS70.
Interface Comments
Interface comments describe what a class or function does. They always go in the .hpp
files and are intended to help other people who want to use our class or functions. We should assume that someone reading our interface comments does not have access to our .cpp
file, so they will rely on these comments to understand what every function and class does. A user of our class does not care about how or why our code works, so interface comments should only discuss behavior, not implementation.
Before every single function declaration, you should place a multiline comment with the following format:
/**
* \brief Returns the quotient of two numbers
* \param numerator The number being divided
* \param denominator The number to divide by
* \returns The result of numerator divided by denominator
* \warning denominator cannot be equal to zero
*/
double divide(double numerator, double denominator);
Once we type /**
and press Return, VS Code should automatically align the following lines. We organize this comment with the following tags, which should appear blue in VS Code.
\brief
: A one line description of what the function does. We must include this for every function.\param <parameter name>
: Describes what a user of the function needs to know about a particular parameter they will pass in. We must include one of these comments for every parameter.\returns
: Describes what the function returns. We must include this for every function that does not returnvoid
.\warning
: Warns the user of any potential dangers associated with the function. This should include any requirements of the parameters or changes in iterator validity. You can include multiple\warning
comments, and each can span multiple lines.\note
: Conveys any additional information that we think the user should know about our function, such as a strange edge case or the asymptotic runtime. You can include multiple\note
comments, and each can span multiple lines.
These tags allow doxygen
to automatically generate well-organized documentation for our code.
We must also include an interface comment for each class declaration. The first line of this comment should be \class <class name>
, and the second should be a \brief
comment. We can also include \note
comments as needed.
/**
* \class Sheep
* \brief A simple sheep implementation with a hat
*/
class Sheep {
minheap.hpp
from the “CS 70 textbook” provides includes interface comments aligning with the expectations of this class.
In order to receive full points on a homework, you must include interface comments which abide by these rules for every class and public function in every .hpp
file you turn in. You are encouraged, but not required, to include these comments for private functions.
Implementation Comments
Unlike interface comments, implementation comments help someone understand how and why our code works. These comments are included in .cpp
files directly next to the code that they describe.
In this section, we will discuss four best practices for implementation comments.
1. Remove any “TODO” comments
The starter code for many homework assignments contains comments beginning with // TODO
which provide instructions and hints. Before submitting an assignment, we must remove all of these comments, since we should have completed all of the TODO
items. We can use the search functionality in VS Code (the magnifying glass on the left pane, or Ctrl+Shift+f) to quickly check if our code contains any TODO
s.
You will lose points if your submission contains any TODO
comments.
2. Avoid Undercommenting
You are expected to include at least some implementation comments on every assignment, and you will always lose points if you do not add any implementation comments. Figuring out the right balance between comments and code is subjective, but for this class, you can generally use the following tips:
- Include at least one implementation comment for every nontrivial function. If a function is only one line, we probably do not need to comment it.
- Include at least one implementation comment for every nontrivial
for
orwhile
loop. This comment should go on the line(s) before the loop and describes the overall purpose of the loop (ex:remove even numbers
,move elements from a to b
). - Include at least one implementation comment for every nontrivial
if
/else
block. If the overall block is simple enough, we can use one comment to describe the overall purpose of theif
and theelse
. If each case is sufficiently complicated, we should probably include a comment describing what each case does. - Include implementation comments for confusing or complicated code. If we ever write a piece of code that we find particularly complicated or confusing, it is usually best to explain it with an implementation comment.
3. Focus on Meaning and Purpose
Implementation comments are far more effective when they focus on the broader meaning and purpose of the code rather than directly translating C++ to English. We should assume that our reader has a basic understanding of C++ syntax. Rather than explaining what a piece of code does line-by-line, we should strive to explain why our approach here was necessary and capture the big picture.
Consider these two examples of commenting a function which prints the elements of an std::vector
to standard output. In the first example, the comments simply translate the C++ syntax and do not add much value.
// Example 1 (poor): Comments simply reiterate the C++ syntax
void printVector(const std::vector<int>& vec) {
// Run this code if !vec.empty() evaluates to true
if (!vec.empty()) {
// Print vec[0] to std::cout
std::cout << vec[0];
}
// Run a for loop with i starting at one, and increase i by one every time as
// long as i is less than vec.size()
for (size_t i = 1; i < vec.size(); ++i) {
// Print a comma and the ith entry of vec to std::cout
std::cout << "," << vec[i];
}
// Print std::endl to std::cout
std::cout << std::endl;
}
In the second example, the comments explain the “big-picture behavior” of the code. Notice that we explain why the if
case is necessary rather than just describing exactly when it will be run. Since the purpose of std::cout << std::endl
is immediately obvious from a direct translation of the syntax, we do not need to comment that line.
// Example 2 (better): Comments focus on broader meaning of the code
void printVector(const std::vector<int>& vec) {
// We need to print the first element of vec seperately to avoid putting a
// comma before it (as long as vec is not empty)
if (!vec.empty()) {
std::cout << vec[0];
}
// Print the remaining elements of vec seperated by commas
for (size_t i = 1; i < vec.size(); ++i) {
std::cout << "," << vec[i];
}
std::cout << std::endl;
}
4. Avoid Overcommenting
If we include too many implementation comments, they can clutter our code and distract from the overall meaning. The appropriate amount of commenting for code varies based on both context and programming language, but for this class, you should consider it a red flag if you have a comment for every line of code. Oftentimes, excessive commenting suggests that you are translating syntax rather than focusing on the big-picture meaning (see the previous section for an example).
In general, you should include a comment for every idea, not for every line of code. For example, a for
loop often encompasses a single idea, so it is often better to include a comment describing the purpose of the overall loop rather than a comment for every line of the loop.
If the purpose of a line of code is immediately obvious, there's no need to not explain it with a comment. For example, return <variable>
, ++<variable>
, and std::cout << std::endl
don't need comments, unless there is some unusual circumstance attached to them.
(When logged in, completion status appears here.)