%   15-212 Lisp Style Guide
%
% Written by Dave Touretzky, with contributions from Steve Shafer,
% Andrew Moore, and John (aka Allen) Miller.
%
% Version of December 23, 1994

\documentstyle[11pt,fullpage]{article}

\begin{document}

\begin{center}
\Large\bf
Lisp Style Guide for 15-212\\
\large\bf
Version 3, as of \today
\end{center}


\section{Comments}

Every function should be preceded by comments that describe its arguments,
inputs, outputs, and side effects (if any.)  For complex functions,
comments should also be included in the body whenever something obscure is
being done.

\begin{verbatim}
;;; (factorial n)  -- compute the factorial of a number.
;;; Inputs:
;;;    n   a non-negative integer
;;; Outputs:
;;;    For valid input, the factorial.  For invalid input,
;;;    signals an error.
;;; Side effects:
;;;    Uses the TIME function to display runtime statisics.
;;; Note: this function produces different output when compiled.

(defun factorial (n)
  (check-type n (integer 0 *))
  ;; demonstrate use of in-line helper function 
  (labels ((fact-helper (n)
             (if (zerop n)  ; a built-in test for zero
                 1
                 (* n (fact-helper (1- n))))))
    (time (fact-helper n))))
\end{verbatim}

As a general convenction (but not strictly enforced), top-level comments
begin with three semicolons.  Comments indented within the body of a
function begin with two semicolons.  Comments appended to the end of a line
of code begin with a single semicolon.

\section{Indentation}

Good Lisp editors automatically handle indentation for you, but you still
need to decide where to put the line breaks.  In general, try to stick to
an 80 character line length, as this makes it easier to print out the code.

In general, all the arguments to a function should be indented the same
way, either all on the same line, or each on a different line at the same
column.  Normally the first argument goes on the same line as the function
name, but for deeply nested code with long function names you can format
things more compactly by putting the first argument on a separate line:

\begin{verbatim}
(defun short-function (x y)
  (list (cons x y)
        (cons y x)
        (list (list x) (list y) (list x y))))


(defun long-function (appetizer main-course dessert)
  (deliver-meal-to-client
    *current-client*
    (prepare-meal-from-ingredients
      (list appetizer main-course dessert))))
\end{verbatim}

\section{Bulletproofing}

User-level functions should do weak bulletproofing using {\tt check-type}
when possible.  This macro automatically generates a helpful error message
if the check fails.

If other types of tests on the input are needed, they should be done after
the {\tt check-type}.  In the example below, note that the check for a
failed hash table retrieval is done by {\tt (when (null contest) $\ldots$)}
rather than by {\tt (unless contest $\ldots$)}, because using an explicit
predicate to check for a null result is considered better style.

\begin{verbatim}
(defun get-winners (name)
  (check-type name string)
  (let ((contest (gethash name *contest-table*)))
    (when (null contest)
      (error "get-winners could not find a contest named ~A~%"
             name))
    (remove-if-not #'winner-p (contest-players contest))))
\end{verbatim}

\section{Variables}
\begin{itemize}

\item Do not use lowercase {\tt l} as a variable name; it looks too much like the
number 1.

\item For function arguments that are supposed to be structures, a common
convention (but it's not required) is to use the structure name as the
variable name:

\begin{verbatim}
(defun turn (ship n)
  (check-type ship ship)
  (check-type n real)
  (setf (ship-heading ship)
        (+ n (compute-present-heading ship))))
\end{verbatim}

\item  Global variables must have names that begin and end with an asterisk, such as
{\tt *contest-table*}.

\item Variables whose values will change as the program runs should be
declared with {\tt defvar}.  Note that if a variable is defined with {\tt
defvar}, evaluating another {\tt defvar} will not change the variable's
value.  So if you re-load the source file, this will not reinitialize any
variables defined this way.

\item Variables whose values will not normally change while the program is
running should be declared with {\tt defparameter}.

\item Constants may be defined using {\tt defconstant}.  Their names should
not begin and end with an asterisk.  An example of a built-in constant is
{\tt pi}.

\item Local variables must be created with {\tt let}, not {\tt setf}.

\begin{verbatim}
(defun bad-code (x)
  (setf y (cons x x)) ; bad use of assignment
  (format t "~A self-consed is ~A~%" x y))

(defun good-code (x)
  (let ((y (cons x x)))
    (format t "~A self-consed is ~A~%" x y)))
\end{verbatim}

\end{itemize}

\section{Conditional Syntax}

Lisp provides lots of conditionals: {\tt if}, {\tt cond}, {\tt when}, {\tt
unless}, {\tt case}, {\tt ecase}, {\tt typecase}, and {\tt etypecase}.  The
{\tt and} and {\tt or} functions may also be used as conditionals.  Part of
good style is to use the right function for each job.

\begin{itemize}

\item {\tt if} is perfect if you're trying to compute a value and there are
only two choices.  It's also useful if you want to take a single action
based on some test:

\begin{verbatim}
(setf rate (if taxable 1.07 1.0))

(if clear-window-flag
    (egad-clear-window *window*))
\end{verbatim}

\item If multiple actions are required when the test is true, use {\tt
when} or {\tt unless}.  Do not use {\tt if} with a {\tt progn}; that's poor
style.

\begin{verbatim}
(defun test (n)
  (unless (numberp n)
    (warn "TEST didn't like its input of ~A.  Using 0 instead." n)
    (setf n 0))
  (unless (integerp n)
    (warn "Fractional input to TEST:  ~A.  Rounding." n)
    (setf n (round n)))
  (/ n (1+ n))))
\end{verbatim}

In general it's not good style to {\tt setf} an argument of a function;
using {\tt let} is better.  The type of error correction shown above is one
of the few exceptions to this rule.

\item If a conditional involves more than two alternatives, use {\tt cond}
rather than nested {\tt if}'s.

\begin{verbatim}
(defun signum (n)
  (check-type n number)
  (cond ((minusp n) -1)
        ((plusp n) 1)
        (t 0)))
\end{verbatim}

\newpage

\item For type dispatch, use {\tt etypecase} rather than {\tt cond}.  This
eliminates writing lots of explicit calls to {\tt typep}, and it can avoid
bugs caused by trying to guess what {\tt type-of} will return, which may be
implementation-dependent.

\begin{verbatim}
(defun get-object-number (obj)
  (etypecase obj
    (dot (dot-number obj))
    (circle (circle-number obj))
    (line (line-number obj))))
\end{verbatim}

\end{itemize}

\section{Generalized Assignment}

It's more concise (and better style) to use generalized assignment macros
for operations such as updating a counter ({\tt incf} or {\tt decf}) or a
list ({\tt push} or {\tt pop}), rather than using {\tt setf}.  In some cases
it's also more efficient.

\begin{verbatim}
(defun inefficient-update (arr i s k val)
  ;; computes the array index twice
  (setf (aref arr (+ i (* s k))) 
        (+ val (aref arr (+ i (* s k))))))

(defun efficient-update (arr i s k val)
  ;; computes the array index once
  (incf (aref arr (+ i (* s k))) val))
\end{verbatim}

\section{Grading Criteria}

Assignments are graded 60\% on correctness and 40\% on style.  Hence, a
program that functions correctly but is atrociously written will not
receive a grade below 60.  Doing well in the course obviously requires
attention to both factors.

\subsection{Fundamentals}
 Assignments must begin with assignment number and the name, Andrew userid,
and section of each student.  The file should also indicate whether the
assignment was done on Andrew or the Mac.  Example:

\begin{verbatim}
  ;;; Dave Touretzky (dt50), Section F:  15-212 Fall 1994 Assignment 17
  ;;; Macintosh Common Lisp
\end{verbatim}

 Students are expected to turn in programs that load without error.  (The
programs might get errors when run, but they should at least {\em load}
successfully.)  To verify that a file is loadable, first get out of Lisp.
Start up a fresh Lisp and type {\tt (load "filename")}, or use the Load
File item under the Tools menu in MCL.  If loading a file generates an
error that leaves Lisp in the debugger, the penalty is 2 points.

 Graders are expected to indicate the reason for every point taken off.
Merely circling the offending bit of code is not enough; they should write
down what the correct code should be, or briefly state in English what the
problem is.

\subsection{Correctness}
 What we're really trying to measure is: Does the student have the correct
concepts for writing this program?  In cases where the program does not
produce correct results, the grader should try to determine why before
taking points off.  A minor error in a shared routine, or an identical
error repeated in several places, might break several otherwise correct
parts of the program.  This should not be penalized as severely as multiple
errors occurring throughout the program that suggest a fundamental lack of
understanding.

Example of a correctness error: a window is 300 pixels wide.  The student
writes a draw-dot routine that range-checks its arguments.  Instead of
checking {\tt (<= 0 x 299)} the student writes {\tt (<= 0 x 300)}, so the
program fails to catch an invalid input of 300.  Take off 1 point for the
range-check error.  If the error is repeated in other functions, the grader
may mark the error on the listing but should not take off additional
points.

Sometimes students implement additional functionality not required by the
assignment.  Do not take off points for this, even if the extra functions
don't work correctly.  We don't want to penalize students for
experimenting, or indulging their creativity.

\subsection{Style}
 Style errors such as lack of comments, sloppy indentation, failure to use
{\tt let} appropriately, and so on, are typically worth 1-2 points each.
It's up to the grader to determine the severity of a mistake.  He or she
should not generally take off additional points for repeating the same
error in several places, but it's up to the grader to determine this.  For
example, if the student writes no documentation for any functions, despite
the fact that they were explicitly told to do this, the grader should take
off 5 or 10 points for that, depending on how important the documentation
component is to this assignment.

 Many style errors are possible beyond the ones listed here.  In some cases
the grader may decide to note an error without taking points off.  For
example, writing {\tt \#'(lambda (x) (numberp x))} instead of {\tt
\#'numberp} is needlessly verbose, but if this is the first assignment
using lambda expressions, it need not cost the student points.

\subsection{Efficiency}

The style portion of the assignment also covers efficiency.  If the student
uses a quadratic algorithm where a linear one was easily available, they
should lose style points for that.  (Exception: if the assignment
explicitly demanded a linear algorithm, then there is a correctness and not
a style problem.)  Common examples of quadratic algorithm mistakes are:

\begin{enumerate}

\item Processing the elements of a list in order by using a counter and the
{\tt nth} function, instead of {\tt dolist} or {\tt map}.

\item Building up a list by using {\tt append} to add elements to the end.
This not only takes quadratic time, it generates quadratic amounts of
garbage as well.  The preferred algorithm uses {\tt cons} and {\tt reverse}
(or better yet, {\tt nreverse}.)  A solution using {\tt nconc} would still
be quadratic but would not generate any garbage.

\end{enumerate}

For bad algorithm mistakes like the ones above, take off 3 points.  For
lesser mistakes, such as computing something twice instead of using {\tt
let} to bind the result, take off 1 point.

\subsection{GUI Assignments}

For assignments involving a GUI (Graphic User Interface), the 40 style
points are assigned based on the appearance and usability of the interface,
and the appropriate use of graphic elements.  Take off at most 10 points in
each of the following categories:

\begin{enumerate}

\item Understandability of the interface.

\begin{itemize}
\item Is it easy to determine what the current state of the world is?

\item Can you easily find how to perform desired actions?
\end{itemize}

\item Well-chosen and properly used widgets.

\begin{itemize}
\item Is the of use widgets well thought out, or can you see better choices?

\item Are transitory functions (if any) provided by means of pre-emptive windows?

\item Are illegal actions blocked by disabled or unavailable widgets?
\end{itemize}

\item Good visual design.

\begin{itemize}
\item Do widgets line up in a pleasing way?

\item Is it easy to follow what's going on?

\item Is the window too full or too empty?

\item Does the program leave lots of widgets around which serve a purpose
only infrequently?
\end{itemize}

\item Miscellaneous.  Covers coding style, efficiency, and any other
non-GUI issues.
\end{enumerate}

\end{document}
