diff --git a/lispguide.xml b/lispguide.xml index 8ef1dc9..2933ebb 100644 --- a/lispguide.xml +++ b/lispguide.xml @@ -5,7 +5,7 @@
-Revision 1.12 +Revision 1.13
@@ -46,8 +46,27 @@ Robert BrownCommon Lisp is a powerful multiparadigm programming language. With great power comes great responsibility. +
+This guide recommends formatting and stylistic choices designed to make your code easier for other people to understand. + Its guidelines apply to all the Common Lisp code we write at Google, + including our internal applications as well as + free software libraries we maintain and publish. + If you contribute to this code base, + you must follow these guidelines before you submit your patch, + or your code will be fixed to follow the guidelines after you do. +
++ If you're writing Common Lisp code outside Google, + we invite you to consider the guidelines we expound in this guide. + You may apply some or all of them to your own projects, at your leisure. + If you do, we hope that you will find some of them useful. + Even if you don't, we also welcome any remarks or constructive feedback + you may have on how to improve our guide, and + about what alternate styles are available. + Finally, we hope that our discussions will be thought-inspiring + to hackers who read them, especially so to newcomers to Common Lisp.
@@ -141,8 +160,9 @@ Robert Brown
- Permission comes from the OWNERS of your project. + Permission comes from the owners of your project.
+Forgiveness is requested in a comment near the point of guideline violation, @@ -168,7 +188,16 @@ Robert Brown Whatever the case may be, you must still follow these guidelines, as well as other conventional guidelines that have not been formalized in this document. - You MUST follow conventions, because they are important for readability. +
++ You MUST follow conventions. + They are important for readability. + When conventions are followed by default, + violations of the convention are a signal + that something notable is happening and deserves attention. + When conventions are systematically violated, + violations of the convention are a distracting noise + that needs to be ignored.
Conventional guidelines are indoctrination. @@ -451,7 +480,7 @@ Robert Brown
- Use your judgement to distinguish + Use your judgment to distinguish general-purpose versus business-specific code, and open-source the general-purpose parts, while keeping the business-specific parts a trade secret. @@ -630,8 +659,10 @@ Robert Brown
Some line length restriction is better than none at all. - Allowing 100 columns seems better, since good style encourages - the use of descriptive variables and function names. + While old text terminals used to make 80 columns the standard, + these days, allowing 100 columns seems better, + since good style encourages the use of + descriptive variables and function names.
@@ -890,25 +921,31 @@ Robert Brown- You must comment anything complicated - so that the next developer can understand what's going on. - (Again, the "hit by a truck" principle.) + Unless some bit of code is painfully self-explanatory, + document it with a documentation string (also known as docstring).
- Unless some bit of code is painfully self-explanatory, document it.
- Prefer documentation strings to comments
- because the former can be displayed by programming tools, such as IDEs,
+ Documentation strings are destined to be read
+ by the programmers who use your code.
+ They can be extracted from functions, types, classes, variables and macros,
+ and displayed by programming tools, such as IDEs,
or by REPL queries such as (describe 'foo);
- they can also be extracted
- to create web-based documentation or other reference works.
+ web-based documentation or other reference works
+ can be created based on them.
+ Documentation strings are thus the perfect locus to document your API.
+ They should describe how to use the code
+ (including what pitfalls to avoid),
+ as opposed to how the code works (and where more work is needed),
+ which is what you'll put in comments.
- Supply a documentation string (also known as docstring) when defining - top-level functions, types, classes, and macros. + Supply a documentation string when defining + top-level functions, types, classes, variables and macros. Generally, add a documentation string wherever the language allows.
@@ -934,9 +971,7 @@ Robert Brown
nil)
(t
(loop for i from 3 upto (sqrt n) by 2
- do (when (divisorp i n)
- (return-from small-prime-number-p nil)))
- t)))
+ never (divisorp i n)))))
+ Comments are explanations to the future maintainers of the code.
+ Even if you're the only person who will ever see and touch the code,
+ even if you're either immortal and never going to quit,
+ or unconcerned with what happens after you leave
+ (and have your code self-destruct in such an eventuality),
+ you may find it useful to comment your code.
+ Indeed, by the time you revisit your code,
+ weeks, months or years later,
+ you will find yourself a different person from the one who wrote it,
+ and you will be grateful to that previous self
+ for making the code readable.
+
+ You must comment anything complicated
+ so that the next developer can understand what's going on.
+ (Again, the "hit by a truck" principle.)
+
+ Also use comments as a way to guide those who read the code,
+ so they know what to find where.
+
You should include a space between the semicolon and the text of the comment. @@ -1564,7 +1619,7 @@ Robert Brown
@@ -1620,6 +1675,27 @@ Robert Brown and only in cases where it won't surprise the person reading the code, and where it offers significant benefits.
++ Indeed, each special variable constitutes state. + Developers have to mentally track the state of all relevant variables + when trying to understand what the code does and how it does it; + tests have to be written and run with all relevant combinations; + to isolate some activity, care has to be taken to locally bind + all relevant variables, including those of indirectly used modules. + They can hide precious information from being printed in a backtrace. + Not only is there overhead associated to each new variable, + but interactions between variables + can make the code exponentially more complex + as the number of such variables increases. + The benefits have to match the costs. +
++ Note though that a Lisp special variable is not a global variable + in the sense of a global variable in, say, BASIC or C. + As special variables can be dynamically bound to a local value, + they are much more powerful than + global value cells where all users necessarily interfere with each other. +
Good candidates for such special variables are items for which "the current" can be naturally used as prefix, @@ -1640,22 +1716,20 @@ Robert Brown that these functions also have this argument, which clutters the code with boilerplate.
-- Note that a Lisp special variable is not a global variable - in the sense of a global variable in, say, BASIC or C. - As special variables can be dynamically bound to a local value, - they are much more powerful than - global value cells where users all interfere with each other. -
You should treat special variables as though they are per-thread variables. - That is, leave the special variable with no top-level binding at all, + By default, you should leave a special variable + with no top-level binding at all, and each thread of control that needs the variable should bind it explicitly. This will mean that any incorrect use of the variable will result in an "unbound variable" error, and each thread will see its own value for the variable. + Variables with a default global value should usually be + locally bound at thread creation time. + You should use suitable infrastructure + to automate the appropriate declaration of such variables.
@@ -1817,7 +1891,7 @@ Robert Brown Code should not signal conditions from inside the cleanup form ofUNWIND-PROTECT
(unless they are always handled inside the cleanup form),
- or otherwise do non-local exits from cleanup handers
+ or otherwise do non-local exits from cleanup handlers
outside of the handler e.g. INVOKE-RESTART.
- You must not use MOP "intercessory" operations. + You must not use MOP "intercessory" operations at runtime. + You should not use MOP "intercessory" operations at compile-time. + At runtime, they are at worst a danger, at best a performance issue. + At compile-time, it is usually cleaner that + macros should things up the right way on the first pass, + without the need to modify things in a second pass. + MOP intercession is a great tool for interactive development, + and you may enjoy it while debugging; + but you should not use it in normal applications.
If a class definition creates a method @@ -2047,9 +2129,9 @@ Robert Brown
ALEXANDRIA:WITH-GENSYMS,
to make some temporary variables in the generated code.
- Note that if you follow our CALL-WITH- style,
+ Note that if you follow our CALL-WITH style,
you typically expand the code only once, as either
an argument to the auxiliary function, or
the body of a lambda passed as argument to it;
@@ -2450,12 +2532,55 @@ Robert Brown
+ INTERN or UNINTERN at runtime.
+
+ You must not use INTERN at runtime.
+ Not only does it cons,
+ it either creates a permanent symbol that won't be collected
+ or gives access to internal symbols.
+ This creates opportunities for memory leaks, denial of service attacks,
+ unauthorized access to internals, clashes with other symbols.
+
+ You must not INTERN a string
+ just to compare it to a keyword;
+ use STRING= or STRING-EQUAL.
+
+ You must not use UNINTERN at runtime.
+ It can break code that relies on dynamic binding.
+ It makes things harder to debug.
+ You must not dynamically intern any new symbol,
+ and therefore you need not dynamically unintern anything.
+
+ You may of course use INTERN at compile-time,
+ in the implementation of some macros.
+ Even so, it is usually more appropriate
+ to use abstractions on top of it, such as
+ ALEXANDRIA:SYMBOLICATE or
+ ALEXANDRIA:FORMAT-SYMBOL
+ to create the symbols you need.
+
NIL.
+ Appropriately use or avoid using NIL.
@@ -2699,67 +2824,6 @@ Robert Brown
#'FOO rather than 'FOO.
-
- The former, which reads as (FUNCTION FOO),
- refers to the function object, and is properly scoped.
- The latter, which reads as (QUOTE FOO),
- refers to the symbol, which when called
- uses the global FDEFINITION of the symbol.
-
- When using functions that take a functional argument
- (e.g., MAPCAR, APPLY,
- :TEST and :KEY arguments),
- you should use the #' to quote the function,
- not just single quote.
-
- An exception is when you explicitly want dynamic linking, - because you anticipate that - the global function binding will be updated. -
-- Another exception is when you explicitly want to access - a global function binding, - and avoid a possible shadowing lexical binding. - This shouldn't happen often, as it is usually a bad idea - to shadow a function when you will want to use the shadowed function; - just use a different name for the lexical function. -
-
- You must consistently use either #'(lambda ...)
- or (lambda ...) without #' everywhere.
- Unlike the case of #'symbol vs 'symbol,
- it is only a syntactic difference with no semantic impact,
- except that the former works on Genera and the latter doesn't.
- You must use the former style if your code is intended as a library
- with maximal compatibility to all Common Lisp implementations;
- otherwise, it is optional which style you use.
- #' may be seen as a hint
- that you're introducing a function in expression context;
- but the lambda itself is usually sufficient hint,
- and concision is good.
- Choose wisely, but above all,
- consistently with yourself and other developers,
- within a same file, package, system, project, etc.
-
- Note that if you start writing a new system
- in a heavily functional style,
- you may consider using
- lambda-reader,
- a system that lets you use the unicode character λ
- instead of LAMBDA.
- But you must not start using such a syntactic extension
- in an existing system without getting permission from other developers.
-
Note that in Common Lisp,
WHEN and UNLESS return NIL
- when the condition evaluates to NIL.
+ when the condition is not met.
+ You may take advantage of it.
Nevertheless, you may use an IF
to explicitly return NIL
if you have a specific reason to insist on the return value.
+ You should include a fall-through clause (t nil)
+ as the last in your (otherwise nil) as the last in your
You should prefer
- You must not use
- You must not
- You must not use
- You may of course use AND and OR
when it leads to more concise code than using
@@ -3232,49 +3306,6 @@ Robert Brown
- INTERN or UNINTERN at runtime.
- INTERN it at runtime.
- Not only does it cons,
- it either creates a permanent symbol that won't be collected
- or gives access to internal symbols.
- This creates opportunities for memory leaks, denial of service attacks,
- unauthorized access to internals, clashes with other symbols.
- INTERN a string
- just to compare it to a keyword;
- use STRING= or STRING-EQUAL.
- UNINTERN at runtime.
- It can break code that relies on dynamic binding.
- It makes things harder to debug.
- You must not dynamically intern any new symbol,
- and therefore you need not dynamically unintern anything.
- INTERN at compile-time,
- in the implementation of some macros.
- Even so, it is usually more appropriate
- to use abstractions on top of it, such as
- ALEXANDRIA:SYMBOLICATE or
- ALEXANDRIA:FORMAT-SYMBOL
- to create the symbols you need.
-
#'FOO rather than 'FOO.
+
+ The former, which reads as (FUNCTION FOO),
+ refers to the function object, and is properly scoped.
+ The latter, which reads as (QUOTE FOO),
+ refers to the symbol, which when called
+ uses the global FDEFINITION of the symbol.
+
+ When using functions that take a functional argument
+ (e.g., MAPCAR, APPLY,
+ :TEST and :KEY arguments),
+ you should use the #' to quote the function,
+ not just single quote.
+
+ An exception is when you explicitly want dynamic linking, + because you anticipate that + the global function binding will be updated. +
++ Another exception is when you explicitly want to access + a global function binding, + and avoid a possible shadowing lexical binding. + This shouldn't happen often, as it is usually a bad idea + to shadow a function when you will want to use the shadowed function; + just use a different name for the lexical function. +
+
+ You must consistently use either #'(lambda ...)
+ or (lambda ...) without #' everywhere.
+ Unlike the case of #'symbol vs 'symbol,
+ it is only a syntactic difference with no semantic impact,
+ except that the former works on Genera and the latter doesn't.
+ You must use the former style if your code is intended as a library
+ with maximal compatibility to all Common Lisp implementations;
+ otherwise, it is optional which style you use.
+ #' may be seen as a hint
+ that you're introducing a function in expression context;
+ but the lambda itself is usually sufficient hint,
+ and concision is good.
+ Choose wisely, but above all,
+ consistently with yourself and other developers,
+ within a same file, package, system, project, etc.
+
+ Note that if you start writing a new system
+ in a heavily functional style,
+ you may consider using
+ lambda-reader,
+ a system that lets you use the unicode character λ
+ instead of LAMBDA.
+ But you must not start using such a syntactic extension
+ in an existing system without getting permission from other developers.
+
-Revision 1.12 +Revision 1.13