Google Common Lisp Style Guide updated to 1.10,

integrating more feedback from inside and outside Google.
This commit is contained in:
tunes@google.com 2012-10-11 17:06:57 +00:00
parent 8dba399b33
commit 0c584cb624

View File

@ -2,9 +2,10 @@
<?xml-stylesheet type="text/xsl" href="styleguide.xsl"?> <?xml-stylesheet type="text/xsl" href="styleguide.xsl"?>
<GUIDE title="Google Common Lisp Style Guide"> <GUIDE title="Google Common Lisp Style Guide">
<p align="right"> <p align="right">
Revision 1.8 Revision 1.10
</p> </p>
@ -12,9 +13,8 @@ Revision 1.8
Robert Brown Robert Brown
</address> </address>
<address> <address>
Fran&#231;ois-Ren&#233; Rideau <a HREF="mailto:tunes@google.com">Fran&#231;ois-Ren&#233; Rideau</a>
</address> </address>
<address> <address>
@ -490,8 +490,7 @@ Fran&#231;ois-Ren&#233; Rideau
before committing code. before committing code.
</li> </li>
<li> <li>
We should/will/must incorporate code coverage You should incorporate code coverage into your testing process.
into our testing process.
Tests are not sufficient Tests are not sufficient
if they do not cover all new and updated code; if they do not cover all new and updated code;
code that for whatever reason cannot be included in coverage results code that for whatever reason cannot be included in coverage results
@ -531,7 +530,7 @@ Fran&#231;ois-Ren&#233; Rideau
<p> <p>
If you're not sure, consult a dictionary, If you're not sure, consult a dictionary,
Google for alternative spellings, Google for alternative spellings,
or ask a local grammar nazi. or ask a local expert.
</p> </p>
<p> <p>
Here are examples of choosing the correct spelling: Here are examples of choosing the correct spelling:
@ -616,7 +615,7 @@ Fran&#231;ois-Ren&#233; Rideau
<STYLEPOINT title="Indentation"> <STYLEPOINT title="Indentation">
<SUMMARY> <SUMMARY>
<p> <p>
Indent your code the way GNU Emacs does. Indent your code the way a properly configured GNU Emacs does.
</p> </p>
<p> <p>
Indent carefully to make the code easier to understand. Indent carefully to make the code easier to understand.
@ -738,10 +737,10 @@ Fran&#231;ois-Ren&#233; Rideau
(defconstant +golden-ratio64+ #xe08c1d668b756f82 "more digits of the golden ratio") (defconstant +golden-ratio64+ #xe08c1d668b756f82 "more digits of the golden ratio")
(defmacro incf32 (x y) (defmacro incf32 (x y)
"like incf, but for integers modulo 2**32" "Like INCF, but for integers modulo 2**32"
`(setf ,x (logand (+ ,x ,y) #xffffffff))) `(setf ,x (logand (+ ,x ,y) #xffffffff)))
(defmacro incf64 (x y) (defmacro incf64 (x y)
"like incf, but for integers modulo 2**64" "Like INCF, but for integers modulo 2**64"
`(setf ,x (logand (+ ,x ,y) #xffffffffffffffff))) `(setf ,x (logand (+ ,x ,y) #xffffffffffffffff)))
</CODE_SNIPPET> </CODE_SNIPPET>
<p> <p>
@ -1343,7 +1342,8 @@ Fran&#231;ois-Ren&#233; Rideau
It is possible to fake global lexical variables It is possible to fake global lexical variables
with a differently named global variable with a differently named global variable
and a <code>DEFINE-SYMBOL-MACRO</code>. and a <code>DEFINE-SYMBOL-MACRO</code>.
You should not use this trick. You should not use this trick,
unless you first publish a library that abstracts it away.
</p> </p>
<CODE_SNIPPET> <CODE_SNIPPET>
(defconstant +hash-results+ #xbd49d10d10cbee50) (defconstant +hash-results+ #xbd49d10d10cbee50)
@ -1358,26 +1358,31 @@ Fran&#231;ois-Ren&#233; Rideau
</SUMMARY> </SUMMARY>
<BODY> <BODY>
<p> <p>
Name boolean-valued functions with a trailing You should name boolean-valued functions with a trailing
<code>"P"</code> or <code>"-P"</code>, <code>"P"</code> or <code>"-P"</code>,
to indicate they are predicates. to indicate they are predicates.
Generally, you should use Generally, you should use
<code>"P"</code> when the rest of the function name is one word <code>"P"</code> when the rest of the function name is one word
and <code>"-P"</code> when it is more than one word. and <code>"-P"</code> when it is more than one word.
</p> </p>
<p>
A rationale for this convention is given in
<a href="http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node69.html">the CLtL2 chapter on predicates</a>.
</p>
<p> <p>
For uniformity, you should follow the convention above, For uniformity, you should follow the convention above,
and not one of the alternatives below. and not one of the alternatives below.
</p> </p>
<p> <p>
Alternative rules used in some existing packages An alternative rule used in some existing packages
is to always use <code>"-P"</code>, is to always use <code>"-P"</code>.
or to always use <code>"?"</code>. Another alternative rule used in some existing packages
is to always use <code>"?"</code>.
When you develop such a package, When you develop such a package,
you must be consistent with the rest of the package. you must be consistent with the rest of the package.
When you start a new package, When you start a new package,
you should not use such an alternative rule you should not use such an alternative rule
without a very good reason. without a very good documented reason.
</p> </p>
</BODY> </BODY>
</STYLEPOINT> </STYLEPOINT>
@ -1832,6 +1837,24 @@ Fran&#231;ois-Ren&#233; Rideau
Sure, use it for "helper" functions, but not API functions. Sure, use it for "helper" functions, but not API functions.
</p> </p>
</blockquote> </blockquote>
<p>
You should, however, use appropriate declarations
in internal low-level functions
where these declarations are used for optimization.
In addition to providing more speed in production,
declarations are more helpful than assertions
to find bugs at compile-time;
they can still help find dynamic errors
by setting optimization settings low while debugging.
You should not use such declarations
outside internal functions
where it is well-documented how unsafe it is
to use such functions with the wrong arguments;
and you must not call these functions in a way
that could possibly lead to their being passed wrong arguments.
Use <code>check-type</code> to sanitize any input being passed
to such function from uncontrolled sources.
</p>
</BODY> </BODY>
</STYLEPOINT> </STYLEPOINT>
<STYLEPOINT title="Macros"> <STYLEPOINT title="Macros">
@ -1966,8 +1989,22 @@ Fran&#231;ois-Ren&#233; Rideau
could have figure out all by itself, could have figure out all by itself,
when the compiler isn't sufficiently-clever when the compiler isn't sufficiently-clever
and the difference matters. and the difference matters.
Consider using a <code>DEFCONSTANT</code> and its variants, </p>
which would give the value a name explaining what it means. <p>
Whenever you are going to use <code>#.</code>,
you should consider using <code>DEFCONSTANT</code> and its variants,
possibly in an <code>EVAL-WHEN</code>,
to give the value a name explaining what it means.
</p>
<p>
You should use normal computations inside an <code>EVAL-WHEN</code>
rather than <code>#.</code> whenever they are enough for the job.
</p>
<p>
If you don't need the computation to happen at compile-time,
but only at some point before runtime,
you should use <code>LOAD-TIME-VALUE</code>
instead of read-time or compile-time computations.
</p> </p>
</BODY> </BODY>
</STYLEPOINT> </STYLEPOINT>
@ -1990,12 +2027,12 @@ Fran&#231;ois-Ren&#233; Rideau
</p> </p>
<p> <p>
It is usually an error to omit the <code>:execute</code>, It is usually an error to omit the <code>:execute</code>,
for it prevents <code>LOAD</code>ing the source rather than the fasl. because it prevents <code>LOAD</code>ing the source rather than the fasl.
It is usually an error to omit the <code>:load-toplevel</code> It is usually an error to omit the <code>:load-toplevel</code>
(except to modify e.g. readtables and compile-time settings), (except to modify e.g. readtables and compile-time settings),
for it prevents <code>LOAD</code>ing future files because it prevents <code>LOAD</code>ing future files
or interactively compiling code or interactively compiling code
that depend on the effects that happen at compile-time that depends on the effects that happen at compile-time,
unless the current file was <code>COMPILE-FILE</code>d unless the current file was <code>COMPILE-FILE</code>d
within the same Lisp session. within the same Lisp session.
</p> </p>
@ -2038,8 +2075,8 @@ Fran&#231;ois-Ren&#233; Rideau
any sort of method combination that might be in effect for the slot. any sort of method combination that might be in effect for the slot.
Rare exceptions include <code>INITIALIZE-INSTANCE</code> Rare exceptions include <code>INITIALIZE-INSTANCE</code>
and <code>PRINT-OBJECT</code> methods and and <code>PRINT-OBJECT</code> methods and
the initialization of Quake volatile slots accessing normally hidden slots in the low-level implementation of
in <code>INITIALIZE-RECORD</code> methods. methods that provide user-visible abstractions.
Otherwise, you should use accessors, Otherwise, you should use accessors,
<code>WITH-ACCESSORS</code> <code>WITH-ACCESSORS</code>
</p> </p>
@ -2047,15 +2084,23 @@ Fran&#231;ois-Ren&#233; Rideau
<p> <p>
Accessor names generally follow a convention of Accessor names generally follow a convention of
<code>&lt;protocol-name&gt;-&lt;slot-name&gt;</code>, <code>&lt;protocol-name&gt;-&lt;slot-name&gt;</code>,
where an "protocol" in this case loosely indicates where a "protocol" in this case loosely indicates
a set of functions with well-defined behavior; a set of functions with well-defined behavior.
a class can implement all or part of an interface
by defining some methods for (generic) functions in the protocol,
including readers and writers.
No implication of a formal "protocol" concept is intended.
</p> </p>
<p> <p>
For example, if there were a "notional" protocol called No implication of a formal "protocol" concept is necessarily intended,
much less first-class "protocol" objects.
However, there may indeed be an abstract CLOS class
or an
<a href="http://common-lisp.net/~frideau/lil-ilc2012/lil-ilc2012.html">Interface-Passing Style</a> interface
that embodies the protocol.
Further (sub)classes or (sub)interfaces may then implement
all or part of a protocol by defining
some methods for (generic) functions in the protocol,
including readers and writers.
</p>
<p>
For example, if there were a notional protocol called
is <code>pnr</code> with accessors <code>pnr-segments</code> is <code>pnr</code> with accessors <code>pnr-segments</code>
and <code>pnr-passengers</code>, then and <code>pnr-passengers</code>, then
the classes <code>air-pnr</code>, <code>hotel-pnr</code> and the classes <code>air-pnr</code>, <code>hotel-pnr</code> and
@ -2085,7 +2130,7 @@ Fran&#231;ois-Ren&#233; Rideau
some specific class(es). some specific class(es).
</p> </p>
<p> <p>
You must not use generic functions where there is no "notional" protocol. You must not use generic functions where there is no notional protocol.
To put it more concretely, To put it more concretely,
if you have more than one generic function that specializes its Nth argument, if you have more than one generic function that specializes its Nth argument,
the specializing classes should all be descendants of a single class. the specializing classes should all be descendants of a single class.
@ -2324,7 +2369,7 @@ Fran&#231;ois-Ren&#233; Rideau
instead of using a combination of several list accessor functions. instead of using a combination of several list accessor functions.
In this context, using <code>CAR</code> and <code>CDR</code> In this context, using <code>CAR</code> and <code>CDR</code>
instead of <code>FIRST</code> and <code>REST</code> also makes sense. instead of <code>FIRST</code> and <code>REST</code> also makes sense.
However, mind in such cases that it might be more appropriate However, keep in mind that it might be more appropriate in such cases
to use higher-level constructs such as to use higher-level constructs such as
<code>DESTRUCTURING-BIND</code> or <code>FARE-MATCHER:MATCH</code>. <code>DESTRUCTURING-BIND</code> or <code>FARE-MATCHER:MATCH</code>.
</p> </p>
@ -2518,6 +2563,28 @@ Fran&#231;ois-Ren&#233; Rideau
(define-constant +google-url+ "http://www.google.com/" :test #'string=) (define-constant +google-url+ "http://www.google.com/" :test #'string=)
(define-constant +valid-colors+ '(red green blue)) (define-constant +valid-colors+ '(red green blue))
</CODE_SNIPPET> </CODE_SNIPPET>
<p>
Note that with optimizing implementations, such as SBCL or CMUCL,
defining constants this way precludes any later redefinition
short of <code>UNINTERN</code>ing the symbol
and recompiling all its clients.
This may make it "interesting" to debug things at the REPL
or to deploy live code upgrades.
If there is a chance that your "constants" are not going to be constant
over the lifetime of your server processes
after taking into consideration scheduled and unscheduled code patches,
you should consider using
<code>DEFPARAMETER</code> or <code>DEFVAR</code> instead,
or possibly a variant of <code>DEFINE-CONSTANT</code>
that builds upon some future library implementing global lexicals
rather than <code>DEFCONSTANT</code>.
You may keep the <code>+plus+</code> convention in these cases
to document the intent of the parameter as a constant.
</p>
<p>
Also note that <code>LOAD-TIME-VALUE</code> may help you
avoid the need for defined constants.
</p>
</BODY> </BODY>
</STYLEPOINT> </STYLEPOINT>
<STYLEPOINT title="Defining Functions"> <STYLEPOINT title="Defining Functions">
@ -2720,9 +2787,10 @@ Fran&#231;ois-Ren&#233; Rideau
</p> </p>
<p> <p>
You must use <code>=</code> to compare numbers, You must use <code>=</code> to compare numbers,
unless it's really okay for <code>0</code>, unless you really mean for <code>0</code>,
<code>0.0</code> and <code>-0.0</code> to compare unequal! <code>0.0</code> and <code>-0.0</code> to compare unequal,
But then again, you must not usually use exact comparison in which case you should use <code>EQL</code>.
Then again, you must not usually use exact comparison
on floating point numbers. on floating point numbers.
</p> </p>
<p> <p>
@ -3036,7 +3104,7 @@ Fran&#231;ois-Ren&#233; Rideau
</li> </li>
<li> <li>
It is quite unlikely that the code will be changed It is quite unlikely that the code will be changed
in ways that cause the declaration not to be true anymore. in ways that cause the declaration to become false.
</li> </li>
</ol> </ol>
<p> <p>
@ -3120,7 +3188,7 @@ Fran&#231;ois-Ren&#233; Rideau
is also <i>O(n^2)</i> unless you specify <code>:FROM-END T</code>. is also <i>O(n^2)</i> unless you specify <code>:FROM-END T</code>.
In such cases, you must use proper abstractions In such cases, you must use proper abstractions
that cover those cases instead of calling <code>REDUCE</code>, that cover those cases instead of calling <code>REDUCE</code>,
first defining them in a suitable library if needs be. first defining them in a suitable library if need be.
</p> </p>
</BODY> </BODY>
@ -3198,7 +3266,7 @@ Fran&#231;ois-Ren&#233; Rideau
</small> </small>
<p align="right"> <p align="right">
Revision 1.8 Revision 1.10
</p> </p>
@ -3206,9 +3274,8 @@ Revision 1.8
Robert Brown Robert Brown
</address> </address>
<address> <address>
Fran&#231;ois-Ren&#233; Rideau <a HREF="mailto:tunes@google.com">Fran&#231;ois-Ren&#233; Rideau</a>
</address> </address>