Indentation

Introduction

This document applies to Nyquist code written using LISP syntax only. For examples of SAL syntax, please refer to the official CMU Nyquist documentation. The information contained here aims to follow best practices for other dialects of LISP, and compatibility with official CMU Nyquist documentation. There may be minor deviations from other published standards at the discretion of the author of this guide for the purposes of:

  • Clarity,
  • Readability,
  • Ease of writing.

Indentation is literally the type and amount of space at the beginning of each line of code. More generally it is a set of rules for laying out the code text of programs and scripts, including when to use new lines, choice of white-space characters, choice of comment characters, and so on. It is very important to indent Lisp programs correctly. Counting parentheses is NOT a good way to read code, and should not be necessary if the code is indented correctly.

With few exceptions, indentation rules are not a matter of personal opinion, but a matter of shared culture. The rules for properly indenting Lisp programs have evolved over many years in the Lisp community and are extremely important for maintainability. Programs are frequently maintained by people other than the original developer, so they should be written in a way that can be easily read by other LISP programmers.

These are the most common rules for indenting Lisp programs:

General rules

Use spaces

Do NOT use tab characters in LISP code. Tabs are interpreted differently by different text editors and are likely to make your code look like a mess for anyone using a different text editor.

Top-level functions

All top-level function definitions start in column 1. This is not negotiable.

Closing parentheses

Closing parentheses are never preceded by newlines.

Bad

Good

Amount of indentation

Unless more specific rules state otherwise, use two spaces:

Bad

Good

Comments

Dollar , semicolon, or hash + pipe

Audacity uses the “$” (dollar) character in place of semicolons for translatable headers in plug-ins that are shipped with Audacity. This should only be used in plug-ins that are shipped with Audacity as these are the only plug-ins that Audacity has translations for. All other plug-ins and scripts should always use one semicolon. Translatable strings in plug-in headers must be wrapped in the UNDERSCORE function:

Shipped plug-in header

Any other plug-in

The #| and |# symbols may be used to temporarily remove a block of code, but is not recommended for production code:

Good

May be useful while developing but not in production code

Better

Most LISP code editors will highlight these commented lines so that it is obvious that they are commented out.

Bad

Number of semicolons

When a comment refers to the preceding code on the same line, use a single semicolon:

When a comment refers to several lines of code after the comment, use two semicolons:

Comments that document a function should have three semicolons:

or

Comment contents

Be brief and to the point. Use the imperative form when documenting functions. Avoid redundant expressions such as This function….

Bad

Good

Indenting special forms

Special forms each have their own indentation rules. These are some common examples:

“IF” special form

The IF special form has exactly three arguments; The test expression, the then expression, and the else expression. The three arguments should line up vertically:

“WHEN” special form

WHEN takes an arbitrary number of arguments, the first of which is the test. The test is written on the first line, and all the other arguments on separate lines below, indented by two spaces:

Short WHEN statements may be written on a single line, with a single space between the test expression and the expression to be evaluated:

“UNLESS” special form

UNLESS can be though of as the opposite of WHEN. The indentation follow the same pattern as WHEN.

and the single line version:

“IF”, “WHEN” and “UNLESS”: Which to use?

In cases where there are two alternatives, the answer is obviously to use IF, as this is the only one of the three that provides an “ELSE” clause.

When there is only one choice, use “WHEN” for cases where it is more logical to test for a True value, and use “UNLESS” when it is more logical to test for a False value.

Bad

Good

Good

Bad

Bad

Good

“LET” special form

LET is a local block construct that contains symbols with optional initializations, and a block of code expressions to evaluate.

The list of local variables directly follows the LET statement. The code block begins on the next line, indented by two spaces

If the list of local variables is long, it may be split across multiple lines. The list of variables should line up as shown below, but it is acceptable to include multiple short name variables on the final line. The code block is indented 2 spaces relative to the LET line.

Local variables with bindings should normally have one variable + value pair per line:

“LET*” special form

LET* is much like LET except that bindings are evaluated sequentially. As with LET, variable + value pairs should line up vertically, but note that this pushes the start of lines between the normal 2 space columns. The code block is still indented 2 spaces relative to the LET* line.

Observe that sequential evaluation is required in the above example; foo MUST be evaluated before bar.

“DO” special form

DO is a special form block for looping while a test condition is true. Ensure that each local variable binding lines up with the first local variable, and that the test condition clause is indented to line up with the first local variable clause. The code block should be indented two spaces.

The above code will print to the debug window:

and return the value of bar, which then has the value “6”.

“DO*” special form

LET* is much like LET except that the local variable bindings are evaluated sequentially. As with DO*, this means that after the first line, and subsequent local variable bindings should be indented one extra space so that they line up, and the test condition clause must also be indented one extra space.

The above prints to the debug window:

and returns “6”.

“COND” special form

COND evaluates a series of predicate / expression pairs in sequential order. When one of the expressions evaluates to non-NIL, the associated expression or code block is evaluated and the result is returned. If all of the test expressions evaluate to NIL, then NIL is returned.

If the lines are sufficiently short, they may simply be lined up as shown below:

Good

In more complex cases with larger code blocks, you may be tempted to start the code block on a new line, indented by two spaces, but consider rewriting the code so that this is not necessary.

Not nice

The above might be better written as:

Better

“CASE” special form

CASE is a special form that evaluates one expression, which is then compared with a series of values. When a match is found, the code block “action” associated with that value is evaluated and returned as the result.

The dominant style in Nyquist if for the first expression to be on the first line, and the value + action pairs to be indented two spaces below:

However, opinions appear to be divided over the correct way to format the CASE special form, and other styles as shown below may be encountered. The dominant style (above) is encouraged, but whichever style you choose, use it consistently. Do NOT mix styles within a code project.