LFE Style Guide
3 Formatting
3.1 Spelling and Abbreviations
You should use correct spelling in your comments, and most importantly in your identifiers.
English is the Lingua Franca of programming, but both Brittish English and American English spellings are acceptable. Do be consistent within single projects, though -- don't mix spellings.
You should use only common and domain-specific abbreviations, and should be consistent with these abbreviations. You may abbreviate lexical variables of limited scope in order to avoid overly-long symbol names.
If you're not sure, consult a dictionary, Google for alternative spellings, or ask a local expert.
3.2 Line length
You should format source code so that no line is longer than 80 characters.
Some line length restriction is better than none at all. Old text terminals used to make 80 columns the standard, which was inherited from punchcard character widths. That, in turn, was inherited from automated loom card widths. We continue to recommend this width for several reasons:
- When printing code on A4 or US Letter paper sizes, 80-character width source files can be printed without requiring a magnifying glass to read.
- There are times when one does not have the luxury of a wide-screen monitor (e.g., debugging code on a console in a data center), and at those times, we are quite grateful to be looking at code that is 80 characters wide at most.
- Using modern text editors that support multiple panes/frames, one may have 3 to 4 files open side-by-side in a single window, thanks to the 80-char limit.
3.3 Indentation
Indent your code the way a properly configured GNU Emacs does or the way that Sublime Text with the paredit plugin does.
Maintain a consistent indentation style throughout a project.
Indent carefully to make the code easier to understand.
There are several projects that assist with Lisp-indentation in various text editors:
- Emacs:
cl-indent
- Sublime Text:
lispindent
- Vim: various (see the CLiki page)
You should use the indentation provided by these packages (though note that lispindent for Sublime Text does get a few things wrong).
Use indentation to make complex function applications easier to read. When an application does not fit on one line or the function takes many arguments, consider inserting newlines between the arguments so that each one is on a separate line. However, do not insert newlines in a way that makes it hard to tell how many arguments the function takes or where an argument form starts and ends.
Don't do this:
;; Bad
(do-something first-argument second-argument (lambda (x)
(frob x)) fourth-argument last-argument)
Do this instead:
;; Better
(do-something first-argument
second-argument
#'(lambda (x) (frob x))
fourth-argument
last-argument)
3.4 File Header
What to include in the top of source files:
- Module descriptions.
- Copyright for special files.
- Authorship for special files.
What should not be included in the file headers:
- Copyright and licesning info that is the same as the
LICENSE
file. - General authorship info -- use your VCS for that.
Every source file should begin with a brief description of the contents of that file.
After that description, every regular LFE module should start the code
itself with a (defmodule ...)
form. Include files do not have
(defmodule ...)
, but should have a series of (defmacro ...)
,
(defrecord ...)
, etc., forms instead.
In general, copyright and licensing should be listed in the LICENSE
file
at the root of the project, not in the file header. Exceptions should be
made for files that are meant to be distributed independently (e.g.,
scripts, binaries, etc.) or for files that have a differing license from the
rest of the project (for whatever reason).
Each comment line of the file header should be prepended with four (4) semicolons:
;;;; This module does some truly amazing stuff. For example, ...
;;;; ...
3.5 Vertical White Space
You should include one blank line between top-level forms, such as function definitions.
Exceptionally, blank lines can be omitted between simple, closely related defining forms of the same kind, such as a group of related constant definitions.
(defun pi () (* #x12B9B0A1 (math:pow 10 -8)))
(defun golden-ratio () (* #x397BEEF356E6C4 (math:pow 10 -16)))
(defun e ()
(* #xB9FE0D492C1F1BCA8C9CB776B21EA1C8A94019588B (math:pow 10 -50)))
Blank lines can be used to separate parts of a complicated function.
Generally, however, you should break a large function into smaller ones
instead of trying to make it more readable by adding vertical space. If you
can't, you should document with a ;;
comment what each of the separated
parts of the function does.
You should strive to keep top-level forms, including comments but excluding the documentation string, of appropriate length -- preferrably short. Forms extending beyond a single page should be rare and their use should be justfied.
3.6 Horizontal White Space
It is considered very bad style to include extra horizontal whitespace before or after parentheses or around symbols.
You should not place right parentheses by themselves on a line. A set of consecutive trailing parentheses need to appear on the same line.
Don't do this:
;; Very Bad
( defun factorial
( (0) 1)
( (n) (when (> n 0))
( * n ( factorial (- n 1) )
)
)
)
Instead, do this:
;; Better
(defun factorial
((0) 1)
((n) (when (> n 0))
(* n (factorial (- n 1)))))
You should use only one space between forms.
You should not use spaces to vertically align forms in the middle of consecutive lines. An exception is made when the code possesses an important yet otherwise not visible symmetry that you want to emphasize.
;; Bad
(let* ((low 1)
(high 2)
(sum (+ (* low low) (* high high))))
...)
;; Better
(let* ((low 1)
(high 2)
(sum (+ (* low low) (* high high))))
...)
You should align nested forms if they occur across more than one line.
;; Bad
(defun munge (a b c)
(* (+ a b)
c))
;; Better
(defun munge (a b c)
(* (+ a b)
c))
You should set your editor to avoid inserting tab characters in the files you
edit. Tabs cause confusion when editors disagree on how many spaces they
represent. In Emacs, do (setq-default indent-tabs-mode nil)
.