Nyquist Indentation Guide

From Audacity Wiki
Jump to: navigation, search

Indenting Nyquist Code

Introduction

This guide was adapted from an article about Common Lisp. The purpose of publishing here is to provide a guide to common conventions used by LISP programmers.

The term indentation refers to the amount of white space at the beginning of lines of code. But here we use the term in a slightly more general way. We use it to mean all rules for the physical layout of a program, such as when to use newlines, how many semicolons to use in comments, etc. It is very important to indent Common Lisp programs correctly; much more important than to indent C or Java programs. The reason is that experienced Lisp programmers read and understand Lisp code based on indentation as opposed to some other way, such as counting parentheses.

Notice that indentation rules are not a matter of personal taste, but a matter of shared culture. The rules for indenting Lisp programs have evolved over a number of years as a kind of standard in the Lisp community. It is not up to the individual student to invent his or her own indentation rules. The argument is one of maintainability. A program is usually maintained by people other than those who wrote it. Standardized rules for indentation play an important role in facilitating maintenance, in particular of Lisp programs.

In this section, we give the most common rules for indenting Lisp programs, together with the Emacs expressions that accomplish them.

General rules

Top-level functions

All top-level function definitions start in column 1. This is important for compatibility with LISP IDEs that search for the beginning of function definitions in column 1.

Closing parentheses

Closing parentheses are never preceded by newlines. Thus, do not write like this:

  ;;; bad
  (defun f (x)
    (when (< (g x) 3)
       (h x 2)
    )
  )

Instead write like this:

  ;;; good
  (defun f (x)
    (when (< (g x) 3)
       (h x 2)))

The first method may seem better to some people, since it is easier to match parentheses, but as we have already mentioned, readers of Lisp programs do not match parentheses, but use indentation.

The first method also requires more lines for the same code. In general, it is good to keep the number of lines down, so that more code will fit on a page or a screen; subject to the indentation rules, of course.

Amount of indentation

Bulb icon Always indent with spaces, not with tabs.
Tab characters may display differently in different editors and mangle the layout.

Unless more specific rules state otherwise, the level of indentation should be relatively small. We use two characters. Thus, do not write like this:

  ;;; bad
  (defun f (x)
      (when (< (g x) 3)
          (h x 2)))

Instead write like this:

  ;;; good
  (defun f (x)
    (when (< (g x) 3)
      (h x 2)))

The reason for the modest indentation is to lower the probability of lines sticking too far out to the right, which in turn would require more newlines and thus more lines in the program. Again, we try to keep the number of lines down.

Comments

Number of semicolons

Comments in Common Lisp start with a semicolon and end at the end of a line. Over the years, a style has developed that uses between one and four semicolons, according to the scope of the comments.

A single semicolon is used for a comment concerning a single line of code, and located on the same line as the code, for instance:

  (if (< (g x) 2)     ; is it sufficiently small?
      (top-level x)   ; if so, abandon everything
      (h y))          ; otherwise try again

Two semicolons are used for a comment that cover several lines of code. The comment line is lined up the the code lines, and precedes them, like this:

  (when (< (g x) 2)
    ;; reinitialize and abandon everything
    (setf *level-number* 0)
    (top-level x))

Three semicolons are used for comments that explain a function. Such comments always start in column 1, like this:

  ;;; Compute the amount of space between symbols
  ;;; as a list of floating point values.
  (defun compute-spaces (symbols)
    (mapcar #'compute-single-space symbols (cdr symbols)))

Content of comments

As usual, we try to be brief, without losing the information contents. For comments to function definitions, a good idea is to use the imperative form of the verb. This way you can avoid redundant expressions such as ``this function. Do not write like this:

  ;;; This function computes the space between symbols
  ;;; as a list of floating point values
  (defun compute-spaces (symbols)
    (mapcar #'compute-single-space symbols (cdr symbols)))

Instead, write like this:

  ;;; Compute the amount of space between symbols
  ;;; as a list of floating point values.
  (defun compute-spaces (symbols)
    (mapcar #'compute-single-space symbols (cdr symbols)))

Indenting special forms

Each special form has its own indentation rule. Here, we give a list of the most common ones.

Indenting the if special form

The if special form in Common Lisp takes exactly three subexpressions. The subexpressions should be lined up, like this:

  (if (= (f x) 4)
      (top-level x)
      (g x))

Indenting the when and unless special forms

These forms both take an arbitrary number of subexpressions, the first of which is distinguished as the test. We write the test on the same line as the name of the special form, and all the other forms on separate lines, indented by two positions, like this:

  (when (= (f x) 4)
    (setf *level-number* 0)
    (unless *do-not-reinitialize*
      (reinitialize-global-information x)
      (reinitialize-local-information))
    (top-level x))

Indenting the let and let* special forms

These forms both take an arbitrary number of subforms. The first is a list of variable initializations, and the rest are the body of the special form. The variable initializations start on the same line as the name of the special form, and the initializations is lined up. The body is indented by two characters like this:

  (let* ((symbols (mapcar #'compute-symbol l))
         (spaces (mapcar #'compute-space symbols (cdr symbols))))
    (when (verify-spacing symbols spaces)
      (make-spacing permanent spaces)))

Indenting the do and do* special forms

These forms both take an arbitrary number of subforms, the first two of which are distinguished. The first one contains the loop variables and the second is a loop termination form. The rest are the body of the special form. Here is an example:

  (do ((i 1 (1+ i))
       (j (length l) (/ j 2)))
      ((= j 0) i)
    (iterate i j)
    (when (= (f x) 4)
      (setf *level-number* 0)
      (top-level x)))