7

In which order should code in a single lisp file be organised? Is there any common style guideline that allows other lisp programmers to easily understand code?

Googling for lisp style guideline yields plenty results; among them:

However, non appear to discuss how functions and other definitions should be organised within a single source file.

"Clean Code" by Martin Fowler (which is not specifically targeted at Lisp) recommends organising functions/methods top to bottom: first describing the code abstractly and next delving deeper and deeper into details. Which is in my opinion a good way to organise function definitions.

However, when the function definitions are ordered top to bottom, the SBCL REPL gives caught STYLE-WARNING: undefined function: … when loading a lisp file. So apparently SBCL thinks using a function before defining it is bad style.

What is the best practice for the order of definitions? Preferably without resulting in compiler/interpreter warnings.

  • Common Lisp has a complex but sexy macro system. That makes things much more complex. – Basile Starynkevitch Apr 6 '16 at 11:17
  • 1
    That warning seems a bit silly: what if you have two mutually-recursive functions? – Mason Wheeler Apr 6 '16 at 11:51
  • @MasonWheeler For mutually recursive functions, I would use labels or declare my functions before defining them with declaim. – coredump Apr 6 '16 at 12:21
  • REPLs tend to work a little differently, because they are usually used interactively, so don't take their warnings as good normal practice. I'm not familiar with your REPL, but most of them have a paste mode or a compile mode that will work more like a regular compile environment. – Karl Bielefeldt Apr 6 '16 at 13:49
5

For Common Lisp I'm using something like this:

  • files are organized in systems and subsystems (see for example ASDF as a tool for that)
  • you can put everything in one file, but that takes some care
  • larger pieces of Lisp are organized in systems of files (see above) and are usually compiled with the file compiler
  • using compile-file, a file is a compilation unit

Files in a system:

  1. system declaration(s)
  2. package declaration(s)
  3. utility functions
  4. macros
  5. classes
  6. various code
  7. machine/os/implementation specific code
  8. a system for tests

a subsystem in a file:

  1. editor header (mode, package, dialect, text encoding, base, ...)
  2. copyright, license
  3. purpose and usage description
  4. using which package
  5. global configuration vars / data
  6. constants
  7. main classes
  8. condition classes
  9. macros and their support code
  10. generic functions / methods / functions
  11. examples

If you develop, you load the compiled system developed so far and extend it incrementally. Once a new functionality is written and tested -> compile the system again, load it and test it again.

The old book 'Lisp: Style and Design' by Molly M. Miller and Eric Benson describes organizing principles and gives an example. Since this book is old, there is some newer infrastructure and some new tools. But the general principles mentioned in the book are still useful.

3

Common Lisp has both COMPILE and COMPILE-FILE.

An implementation like SBCL does not warn about undefined function if you compile the whole file, for example. Under slime, C-c M-k does not trigger a warning:

(defun bar (x) (foo x))
(defun foo (y) (+ 3 y))

Once it is compiled, loading the .fasl in a fresh Lisp image gives no warning either, though loading the .lisp does, because LOAD for a source file simply execute all forms in sequence.

However, most code that I saw define things from low-level elements and build up higher-level functions later in the file. I don't find it more confusing in that order than in the reverse one, personally. It is quite consistent with the way you define local functions with flet or labels, or even local variables with let. If you need to define mutually recursive functions, you can also declare your functions before defining them:

(declaim (ftype function foo bar baz ...))

Lisp environment supports efficient ways to go to the definition of functions and methods, so I generally rely more on slime-edit-definition.

What matters most IMO to organize your code is probably to think about packages and how they relate to each others.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.