Skip to content

Commented code

Published:

Being able to write comments in code is a common feature of all programming languages, and even markup languages like HTML. Comments are parts of the code that are completely ignored by any software we use to execute/parse the text. The only functionality they provide is to explain, more or less in detail, the sections of code they are associated with. I’ve heard all sorts of opinions about comments. From those who consider them a waste of time, to those who see them as an essential and indispensable tool for any respectable project. As with many programming patterns, I think it all depends on the context. I will try to clarify what I mean with some examples.

Keep it simple, stupid (KISS)

Writing clear and well-structured code is one of the most important skills a programmer can develop, and unfortunately, it requires years of experience and practice. The choice of variable names, file structure, use of functions and classes, are all choices that can facilitate or hinder code understanding. For an intentionally extreme example, if faced with this code snippet in Python,

@lambda _: _()
class _:
    def __format__(_, __):
        _.__class__._ = property(lambda _: print(__))
        return ""

def __() -> f"{_:Hello, world!}": ...

_._

very few would be able to guess its functionality, when in reality it is something trivial:

def print_hello_world():
    print("Hello, world!")

print_hello_world()

This banal observation leads us to a first rule

Note

Don’t write complicated code when it’s not necessary.

Let’s call things by their name

There are two hard things in computer science: cache invalidation and naming things.

— Phil Karlton

Although it is a notoriously unpleasant task, choosing variable and function names is an extremely powerful tool for making the functionality and purpose of the code clear at a glance. Let’s take the following code as an example:

def fun(a0, a1):
    a2 = 1
    for a3 in range(a1):
        a2 *= a0
    return a2

With a little attention, it is not too difficult to understand what this function does, but if we compare it with its equivalent

def pow(base, exp):
    result = 1
    for _ in range(exp):
        result *= base
    return result

the difference is noticeable. The name pow (or power) immediately tells us that this is a function for exponentiation, and the names of the variables base, exp (or exponent), and result implicitly communicate what we can expect from each of them.

Tip

In this specific case, unless we have a valid reason, it would be better to use the ** operator already present in Python.

In short, overcoming the justified laziness, typical of any self-respecting programmer, taking a few extra seconds to choose the appropriate terminology for the context can prevent hours of headaches for anyone who finds themselves reading our masterpieces in the future.

Note

Giving meaningful names to all elements of the code contributes to its intuitive understanding.

A type of help

Another tool that can be useful for making code clearer is the use of explicit types. Some programming languages that have been hugely successful recently, such as Python and JavaScript, make their speed of development and flexibility their strong points. This usually includes a system of dynamic typing. The type of variables is not indicated at the time they are declared, but can change at any time, requiring a runtime check. Although it can be quite convenient for writing quick prototypes, this approach makes it practically impossible to know a variable’s type in advance, and therefore its purpose and the operations we can perform on it. To address what has been almost universally recognized over the years as an inexhaustible source of bugs and oversights, some languages have introduced a type-hinting system that, without introducing strict constraints, allows us to give a hint about the type we expect the variable to have. Let’s examine this code in Python:

def pow(bases, exp):
    if isinstance(bases, (int, float)):
        return [bases ** exp]
    if isinstance(bases, list):
        return [x ** exp for x in bases]

This function calculates the power of a number or a list of numbers and returns a list with the results. Even in this case, given the simplicity of the example, it is not difficult to understand the type of input and output parameters, but everything would be even less ambiguous if we had used type annotations.

def pow(bases: int | float | list[int | float], exp: int) -> list[float]:
    if isinstance(bases, (int, float)):
        return [bases ** exp]
    if isinstance(bases, list):
        return [x ** exp for x in bases]

To those who are not used to it, type annotations may seem a bit verbose, even confusing, but especially in larger projects and if well integrated into your editor, they greatly simplify interfacing with external libraries without having to sift through the source code or documentation. Additionally, if you really want to go the extra mile, you can use tools like mypy or pyright (or equivalent utilities in languages other than Python) to gain extra guarantees about the correctness of the data we expect to provide and receive.

Note

Adding type hints wherever possible, especially in dynamically typed languages, adds useful information to interfaces and makes the code less prone to errors.

No Comment

There are cases where, unfortunately, a clear solution is not possible, or it is simply not immediately evident what we are doing and why. This is especially true in cases where:

  • we need to optimize the code for performance. Operations that are notoriously difficult to interpret, such as using bitwise operations or manipulating pointers, may be necessary.
  • the algorithm requires a deep understanding of the underlying computer science or mathematical theory.
  • we are implementing a known algorithm, but with a particular variant. In this case, it is useful to refer to the original documentation or paper.
  • there are several parameters that non-intuitively influence the functioning of the algorithm.

In these cases, comments become a fundamental tool to avoid being forced to spend an inordinate amount of time reverse engineering what has been written.

def fibonacci(n: int) -> int:
    r"""
    Calculates the n-th Fibonacci number using the
    [Binet's formula](https://en.wikipedia.org/wiki/Jacques_Philippe_Marie_Binet).

    The formula can be expressed as:

    $$
    F(n) = \left\lfloor \frac{\phi^n}{\sqrt{5}} + \frac{1}{2} \right\rfloor
    $$

    where $\phi = \frac{1 + \sqrt{5}}{2}$.

    Args:
        n: Index of the Fibonacci number to calculate.

    Returns:
        n-th number in the sequence.
    """
    phi = (1 + 5 ** 0.5) / 2
    return int((phi ** n) / (5 ** 0.5) + 0.5)

Spend some time studying the syntax of comments in the language you are using, and try to use it consistently. Many editors expect comments to follow a certain structure, such as jsdoc or markdown. Compliant comments will hopefully be displayed to the user rendered decently when hovering over the function or variable.

There is also a benefit that I personally find extremely underrated, which is the automatic generation of documentation directly from comments. There are many tools capable of doing this, such as Sphinx for Python and Doxygen for C/C++ and many others. With very little effort, you can obtain something that can be easily distributed and consulted even by those who do not want to delve into the implementation details.

Note

Comments are a fundamental tool for explaining more complex parts of the code in an understandable way, which would otherwise require a deep knowledge of the techniques used and a significant amount of study time.

Conclusions

To sum up this structured stream of consciousness, I hope to have convinced you that writing code is an activity that requires a bit more thought than one might expect. It is not difficult to fill hundreds of lines of code without even realizing it, but without a bit of discipline, the final result will probably be incomprehensible to anyone, including ourselves after some time. On the other hand, if you develop the habit of following the principles I have tried to present, even if not to the letter and certainly with some customization based on your style and personal taste, writing clear and well-structured code will come naturally and will no longer require any effort. Be careful, though, because then you won’t be able to go back!