From f981c5c266def2fac5aaf38476274b34861c9b30 Mon Sep 17 00:00:00 2001 From: "tunes@google.com" Date: Sun, 14 Oct 2012 13:47:38 +0000 Subject: [PATCH] Google Common Lisp Style Guide, revision 1.12 --- lispguide.xml | 1507 +++++++++++++++++++++++++++++-------------------- 1 file changed, 884 insertions(+), 623 deletions(-) diff --git a/lispguide.xml b/lispguide.xml index 5b4de9c..8ef1dc9 100644 --- a/lispguide.xml +++ b/lispguide.xml @@ -5,7 +5,7 @@

-Revision 1.11 +Revision 1.12

@@ -178,7 +178,7 @@ Robert Brown It is still useful to distinguish the parts that are technically motivated from the parts that are mere conventions, so you know when best to defy conventions for good effect, - and when not to fall into the pits that the conventions are there to help avoid. + and when not to fall into the pitfalls that the conventions are there to help avoid.

@@ -262,10 +262,6 @@ Robert Brown -
  • - Use of i< and friends - (premature optimization, bug introduction) -
  • @@ -511,8 +507,14 @@ Robert Brown (using asdf's :around-compile hooks).
  • - You must run the "precheckin" tests successfully - before committing code. + All code should be checked in an appropriate source control system, + in a way that allows for complete reproducibility of + build, test and execution of + the code that is, has been or may be deployed. +
  • +
  • + You must run the "precheckin" tests, and each component must pass + its unit tests successfully before you commit any code.
  • You should incorporate code coverage into your testing process. @@ -888,7 +890,7 @@ Robert Brown - You should use document strings to explain how code works. + You should use document strings to explain how to use your code.

    @@ -1301,43 +1303,6 @@ Robert Brown

    - - - You should not include a library or package name as a symbol prefix - when naming entities from the library or package. - - -

    - When naming public symbols of a package, - you should not include as a prefix the package name. - Naming functions this way makes them awkward to use - from client package with package-qualified symbols. -

    - - ;; Bad - (in-package #:varint) - (defun varint-length64 () ... ) - - (in-package #:client-code) - (defconst +padding+ (varint:varint-length64 +end-token+)) - - - ;; Better - (in-package #:varint) - (defun length64 () ... ) - - (in-package #:client-code) - (defconst +padding+ (varint:length64 +end-token+)) - -

    - An exception to the above rule would be to include a prefix - for the names of variables that would otherwise be expected to clash - with variables in packages that use the current one. - For instance, ASDF exports a variable *asdf-verbose* - that controls the verbosity of asdf only and the entire Lisp programs. -

    - -
    Name globals according to convention. @@ -1412,172 +1377,46 @@ Robert Brown

    - + + + You should not include a library or package name + as a prefix within the name of symbols. + + +

    + When naming a symbol (external or internal) in a package, + you should not include the package name + as a prefix within the name of the symbol. + Naming a symbol this way makes it awkward to use + from a client package accessing the symbol + by qualifying it with a package prefix, + where the package name then appears twice + (once as a package prefix, + another time as a prefix within the symbol name). +

    + + ;; Bad + (in-package #:varint) + (defun varint-length64 () ... ) - - - - You should avoid side-effects when they are not necessary. - - + (in-package #:client-code) + (defconst +padding+ (varint:varint-length64 +end-token+)) + + + ;; Better + (in-package #:varint) + (defun length64 () ... ) + + (in-package #:client-code) + (defconst +padding+ (varint:length64 +end-token+)) +

    - Lisp is best used as a "mostly functional" language. -

    -

    - Avoid modifying local variables, try rebinding instead. -

    -

    - Avoid creating objects and the SETFing their slots. - It's better to set the slots during initialization. -

    -

    - Make classes as immutable as possible, that is, avoid giving slots - setter functions if at all possible. -

    -

    - Using a mostly functional style makes it much easier - to write concurrent code that is thread-safe. - It also makes it easier to test the code. -

    - -
    - - - Favor iteration over recursion. - - -

    - Common Lisp systems are not required to implement constant space - optimizations for recursive function calls from tail positions; - however, most serious implementations (including SBCL and CCL) - do implement proper tail calls. - Still, even compilers that implement proper tail call do it - only in restricted conditions: -

    -
      -
    • - The (DECLARE (OPTIMIZE ...)) settings - must favor SPEED enough and - not favor DEBUG too much, - for some compiler-dependent meanings of "enough" and "too much". - (For instance, in SBCL, you should avoid (SPEED 0) - and (DEBUG 3) to achieve tail call elimination.) -
    • -
    • - There should not be dynamic bindings around the call - (even though some Scheme compilers are able to properly treat - such dynamic bindings, called parameters in Scheme parlance). -
    • -
    -

    - For compatibility with all compilers and - to avoid stack overflow when debugging, - you should use iteration or the built in mapping functions - rather than relying on proper tail calls. -

    -

    - If you do rely on proper tail calls, - you must prominently document the fact, - and take appropriate measures to ensure an appropriate compiler is used - with appropriate optimization settings. - For fully portable code, you may have to use trampolines instead. -

    - -
    - - - Use special variables sparingly. - - -

    - Using Lisp "special" (dynamically bound) variables - as implicit arguments to functions should be used sparingly, - and only in cases where it won't surprise the person reading the code, - and where it offers significant benefits. -

    -

    - Good candidates for such special variables - are items for which "the current" can be naturally used as prefix, - such as "the current database connection" or - "the current business data source". - They are singletons as far as the rest of the code is concerned, - and often passing them as an explicit argument - does not add anything to the readability or maintainability - of the source code in question. -

    -

    - They can make it easier to write code that can be refactored. - If you have a request processing chain, - with a number of layers that all operate upon a "current" request, - passing the request object explicitly to every function - requires that every function in the chain have a request argument. - Factoring out code into new functions often requires - 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, - they are much more powerful than - global value cells that can be changed from everywhere. -

    -

    - 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, - 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. -

    - - -
    - - - Be consistent in assignment forms. - - -

    - There are several styles for dealing with assignment and side-effects; - whichever a given package is using, - keep using the same consistently when hacking said package. - Pick a style that makes sense when starting a new package. -

    -

    - Regarding multiple assignment in a same form, there are two schools: - the first style groups as many assignments as possible into a single - SETF or PSETF form - thus minimizing the number of forms with side-effects; - the second style splits assignments into as many individual - SETF (or SETQ, see below) forms as possible, - to maximize the chances of locating forms that modify a kind of place - by grepping for (setf (foo .... - A grep pattern must actually contain as many place-modifying forms - as you may use in your programs, which may make this rationale either - convincing or moot depending on the rest of the style of your code. - You should follow the convention used in the package you are hacking. - We recommend the first convention for new packages. -

    -

    - Regarding SETF and SETQ, - there are two schools: - this first regards SETQ - as an archaic implementation detail, - and avoids it entirely in favor of SETF; - the second regards SETF - as an additional layer of complexity, - and avoids it in favor of SETQ whenever possible - (i.e. whenever the assigned place is a variable or symbol-macro). - You should follow the convention used in the package you are hacking. - We recommend the first convention for new packages. -

    -

    - In the spirit of a mostly pure functional style, - which makes testing and maintenance easier, - we invite you to consider how to do things with the fewest assignments required. + An exception to the above rule would be to include a prefix + for the names of variables that would otherwise be expected to clash + with variables in packages that use the current one. + For instance, ASDF exports a variable *ASDF-VERBOSE* + that controls the verbosity of ASDF only, + rather than of the entire Lisp program.

    @@ -1605,7 +1444,8 @@ Robert Brown

    As an exception, unit tests may use the internals of the package being tested. - So when you refactor, look at the package's unit tests. + So when you refactor, watch out for + internals used by the package's unit tests.

    The :: construct is also useful for very temporary hacks, @@ -1614,6 +1454,16 @@ Robert Brown the externally-visible definition of the package, export it.

    +

    + You may find that some internal symbols represent concepts + you usually want to abstract away and hide under the hood, + yet at times are necessary to expose for various extensions. + For the former reason, you do not want to export them, + yet for the latter reason, you have to export them. + The solution is to have two different packages, + one for your normal users to use, and + another for the implementation and its extenders to use. +

    Each package is one of two types:

    @@ -1683,6 +1533,179 @@ Robert Brown + + + + + + You should avoid side-effects when they are not necessary. + + +

    + Lisp is best used as a "mostly functional" language. +

    +

    + Avoid modifying local variables, try rebinding instead. +

    +

    + Avoid creating objects and the SETFing their slots. + It's better to set the slots during initialization. +

    +

    + Make classes as immutable as possible, that is, avoid giving slots + setter functions if at all possible. +

    +

    + Using a mostly functional style makes it much easier + to write concurrent code that is thread-safe. + It also makes it easier to test the code. +

    + +
    + + + Favor iteration over recursion. + + +

    + Common Lisp systems are not required to implement + function calls from tail positions without leaking stack space + — which is known as proper tail calls (PTC), + tail call elimination (TCE), + or tail call optimization (TCO). + This means that indefinite recursion through tail calls + may quickly blow out the stack, + which hampers functional programming. + Still, most serious implementations (including SBCL and CCL) + do implement proper tail calls, but with restrictions: +

    +
      +
    • + The (DECLARE (OPTIMIZE ...)) settings + must favor SPEED enough and + not favor DEBUG too much, + for some compiler-dependent meanings of "enough" and "too much". + (For instance, in SBCL, you should avoid (SPEED 0) + and (DEBUG 3) to achieve proper tail calls.) +
    • +
    • + There should not be dynamic bindings around the call + (even though some Scheme compilers are able to properly treat + such dynamic bindings, called parameters in Scheme parlance). +
    • +
    +

    + For compatibility with all compilers and optimization settings, + and to avoid stack overflow when debugging, + you should prefer iteration or the built in mapping functions + to relying on proper tail calls. +

    +

    + If you do rely on proper tail calls, + you must prominently document the fact, + and take appropriate measures to ensure an appropriate compiler is used + with appropriate optimization settings. + For fully portable code, you may have to use trampolines instead. +

    + +
    + + + Use special variables sparingly. + + +

    + Using Lisp "special" (dynamically bound) variables + as implicit arguments to functions should be used sparingly, + and only in cases where it won't surprise the person reading the code, + and where it offers significant benefits. +

    +

    + Good candidates for such special variables + are items for which "the current" can be naturally used as prefix, + such as "the current database connection" or + "the current business data source". + They are singletons as far as the rest of the code is concerned, + and often passing them as an explicit argument + does not add anything to the readability or maintainability + of the source code in question. +

    +

    + They can make it easier to write code that can be refactored. + If you have a request processing chain, + with a number of layers that all operate upon a "current" request, + passing the request object explicitly to every function + requires that every function in the chain have a request argument. + Factoring out code into new functions often requires + 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, + 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. +

    + + +
    + + + Be consistent in assignment forms. + + +

    + There are several styles for dealing with assignment and side-effects; + whichever a given package is using, + keep using the same consistently when hacking said package. + Pick a style that makes sense when starting a new package. +

    +

    + Regarding multiple assignment in a same form, there are two schools: + the first style groups as many assignments as possible into a single + SETF or PSETF form + thus minimizing the number of forms with side-effects; + the second style splits assignments into as many individual + SETF (or SETQ, see below) forms as possible, + to maximize the chances of locating forms that modify a kind of place + by grepping for (setf (foo .... + A grep pattern must actually contain as many place-modifying forms + as you may use in your programs, which may make this rationale either + convincing or moot depending on the rest of the style of your code. + You should follow the convention used in the package you are hacking. + We recommend the first convention for new packages. +

    +

    + Regarding SETF and SETQ, + there are two schools: + this first regards SETQ + as an archaic implementation detail, + and avoids it entirely in favor of SETF; + the second regards SETF + as an additional layer of complexity, + and avoids it in favor of SETQ whenever possible + (i.e. whenever the assigned place is a variable or symbol-macro). + You should follow the convention used in the package you are hacking. + We recommend the first convention for new packages. +

    +

    + In the spirit of a mostly pure functional style, + which makes testing and maintenance easier, + we invite you to consider how to do things with the fewest assignments required. +

    + +
    You must make proper usage of assertions and conditions. @@ -1804,7 +1827,7 @@ Robert Brown hiding the rest. And the rest is the part we really care about! - ;; WRONG WAY + ;; Bad (handler-case (catch 'ticket-at (etd-process-blocks)) @@ -1813,7 +1836,7 @@ Robert Brown (error c))) - ;; RIGHT WAY + ;; Better (unwind-protect (catch 'ticket-at (etd-process-blocks)) @@ -1872,217 +1895,6 @@ Robert Brown

    - - - Use macros when appropriate, which should be sparingly and carefully. - - -

    - You must never use a macro where a function will do. - That is, if the semantics of what you are writing - conforms to the semantics of a function, - then write it as a function rather than a macro. -

    -

    - You must not use a macro for performance reasons. - If profiling shows that you have a performance problem - with a specific function, - document the need and profiling-results appropriately, - and - DECLAIM to that function INLINE. -

    - -

    - You can also use "compiler-macros" - as a way to speed up function execution - by specifying a source-to-source transformation. - Beware that it interferes with tracing the optimized functions. -

    -

    - When you write a macro-defining macro - (a macro that generates macros), - comment it particularly clearly, - since these are hard for the uninitiated to understand. -

    -

    - Using Lisp macros properly requires taste. - Avoid writing complicated macros - unless the benefit clearly outweighs the cost. - It takes more effort for your fellow developers to learn your macro, - so you should only use a macro if the gain in expressiveness - is big enough to justify that cost. - As usual, feel free to consult your colleagues if you're not sure, - since without a lot of Lisp experience, - it can be hard to make this judgment. -

    -

    - You must not define new reader macros. -

    -

    - If your macro has a parameter that is a Lisp form - that will be evaluated when the expanded code is run, - you should name the parameter with the suffix -form. - This convention helps make it clearer to the macro's user - which parameters are Lisp forms to be evaluated, and which are not. -

    -

    - One way to write a macro is the so-called "call-with" style, - explained at length in - http://random-state.net/log/3390120648.html. - The general principle is that the macro is strictly limited to processing the syntax, - and as much of the semantics as possible is kept in normal functions. - Therefore, a macro WITH-FOO is often limited to - generating a call to an auxiliary function - CALL-WITH-FOO - with arguments deduced from the macro arguments. - Macro &body arguments are typically - wrapped into a lambda expression of which they become the body, - which is passed as one of the arguments of the auxiliary function. -

    -

    - The advantages are many. - By keeping semantics outside the macro, - the macro is made simpler, easier to get right, and less subject to change, - which makes it easier to develop and maintain. - The semantics is written in a simpler language — one without staging — - which also makes it easier to develop and maintain. - It becomes possible to debug and update the semantic function - without having to recompile all clients of the macro. - The semantic function appears in the stack trace - which also helps debug client functions. - The macro expansion is made shorter and - each expansion shares more code with other expansions, - which reduces memory pressure which in turn usually makes things faster. - You should use this style unless the macro is used - in tight loops where performance matters; - and even then, see our rules regarding optimization. -

    -

    - Any functions (closures) created by the macro should be named: - either use FLET or NAMED-LAMBDA. - Using FLET is also good - because you can declare the function to be of dynamic - extent (if it is — and often it is). -

    -

    - If a macro call contains a form, - and the macro expansion includes more than one copy of that form, - the form can be evaluated more than once, - and code it contains macro-expanded and compiled more than once. - If someone uses the macro and calls it - with a form that has side effects or that takes a long time to compute, - the behavior will be undesirable - (unless you're intentionally writing - a control structure such as a loop). - A convenient way to avoid this problem - is to evaluate the form only once, - and bind a (generated) variable to the result. - There is a very useful macro called ALEXANDRIA:ONCE-ONLY - that generates code to do this. - See also ALEXANDRIA:WITH-GENSYMS, - to make some temporary variables in the generated code. - 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; - you therefore avoid the above complexity. -

    -

    - When you write a macro with a body, - such as a WITH-xxx macro, - even if there aren't any parameters, - you should leave space for them anyway. - For example, if you invent WITH-LIGHTS-ON, - do not make the call to it look like - (defmacro with-lights-on (&body b) ...). - Instead, do (defmacro with-lights-on (() &body b) ...). - That way, if parameters are needed in the future, - you can add them without necessarily having to change - all the uses of the macro. -

    - -
    - - - You should use #. sparingly, - and you must avoid read-time side-effects. - - -

    - The #. standard read-macro - will read one object, evaluate the object, and - have the reader return the resulting value. -

    -

    - It is mainly used as a quick way - to get something evaluated at compile time - (actually "read time" but it amounts to the same thing). - If you use this, the evaluation MUST NOT have any side effects - and MUST NOT depend on any variable global state. - The #. should be treated as a way - to force "constant-folding" - that a sufficiently-clever compiler - could have figure out all by itself, - when the compiler isn't sufficiently-clever - and the difference matters. -

    -

    - Whenever you are going to use #., - you should consider using DEFCONSTANT and its variants, - possibly in an EVAL-WHEN, - to give the value a name explaining what it means. -

    -

    - You should use normal computations inside an EVAL-WHEN - rather than #. whenever they are enough for the job. -

    -

    - If you don't need the computation to happen at compile-time, - but only at some point before runtime, - you should use LOAD-TIME-VALUE - instead of read-time or compile-time computations. -

    - -
    - - - When using EVAL-WHEN, you should almost always use all of - (:compile-toplevel :load-toplevel :execute). - - -

    - Lisp evaluation happens at several times, - some of them interleaved. - Be aware of them when writing macros. - EVAL-WHEN considered harmful to your mental health. -

    -

    - In summary of the article linked above, - unless you're doing truly advanced macrology, - the only valid combination in an EVAL-WHEN - is to include all of - (eval-when (:compile-toplevel :load-toplevel :execute) ...) -

    -

    - It is usually an error to omit the :execute, - because it prevents LOADing the source rather than the fasl. - It is usually an error to omit the :load-toplevel - (except to modify e.g. readtables and compile-time settings), - because it prevents LOADing future files - or interactively compiling code - that depends on the effects that happen at compile-time, - unless the current file was COMPILE-FILEd - within the same Lisp session. -

    -

    - In some odd cases, you may want to evaluate top-level definitions - from within the expansion of a DEFTYPE - or of a non-top-level DEFMACRO. - In these cases, you should use ASDF-FINALIZERS - and its ASDF-FINALIZERS:EVAL-AT-TOPLEVEL form. -

    - -
    Use CLOS appropriately. @@ -2243,6 +2055,403 @@ Robert Brown + + + + Use macros when appropriate, which is often. + Define macros when appropriate, which is seldom. + + +

    + Macros bring syntactic abstraction, which is a wonderful thing. + It helps make your code clearer, by describing your intent + without getting bogged in implementation details + (indeed abstracting those details away). + It helps make your code more concise and more readable, + by eliminating both redundancy and irrelevant details. + But it comes at a cost to the reader, + which is learning a new syntactic concept for each macro. + And so it should not be abused. +

    +

    + The general conclusion is that there shouldn't be + any recognizable design pattern + in a good Common Lisp program. + The one and only pattern is: use the language, + which includes defining and using syntactic abstractions. +

    +

    + Existing macros must be used + whenever they make code clearer + by conveying intent in a more concise way, + which is often. + When a macro is available in your project + that expresses the concept you're using, + you must not write the expansion rather than use the macro. +

    +

    + New macros should be defined as appropriate, + which should be seldom, + for common macros have already been provided + by the language and its various libraries, + and your program typically only needs few new ones + relative to its size. +

    +

    + You should follow the OAOOM rule of thumb + for deciding when to create a new abstraction, + whether syntactic or not: + if a particular pattern is used more than twice, + it should probably be abstracted away. + A more refined rule to decide when to use abstraction + should take into account + the benefit in term of number of uses and gain at each use, + to the costs in term of having to get used to reading the code. + For syntactic abstractions, costs and benefits to the reader + is usually more important than costs and benefits to the writer, + because good code is usually written once + and read many times by many people + (including the same programmer + who has to maintain the program after having forgotten it). + Yet the cost to the writer of the macro + should also be taken into account; + however, in doing so it should rather be compared + to the cost of the programmer writing other code instead + that may have higher benefits. +

    +

    + Using Lisp macros properly requires taste. + Avoid writing complicated macros + unless the benefit clearly outweighs the cost. + It takes more effort for your fellow developers to learn your macro, + so you should only use a macro if the gain in expressiveness + is big enough to justify that cost. + As usual, feel free to consult your colleagues if you're not sure, + since without a lot of Lisp experience, + it can be hard to make this judgment. +

    +

    + You must never use a macro where a function will do. + That is, if the semantics of what you are writing + conforms to the semantics of a function, + then you must write it as a function rather than a macro. +

    +

    + You must not transform a function into a macro for performance reasons. + If profiling shows that you have a performance problem + with a specific function FOO, + document the need and profiling-results appropriately, + and + (declaim (inline foo)). +

    + +

    + You can also use a compiler-macro + as a way to speed up function execution + by specifying a source-to-source transformation. + Beware that it interferes with tracing the optimized function. +

    +

    + When you write a macro-defining macro + (a macro that generates macros), + document and comment it particularly clearly, + since these are hard for the uninitiated to understand. +

    +

    + You must not install new reader macros + without a consensus among the developers of your system. + Reader macros must not leak out of the system that uses them + to clients of that system or other systems used in the same project. + You must software such as + cl-syntax or named-readtables + to control how reader macros are used. + This clients who desire it may use the same reader macros as you do. + In any case, your system must be usable + even to clients who do not use these reader macros. +

    +

    + If your macro has a parameter that is a Lisp form + that will be evaluated when the expanded code is run, + you should name the parameter with the suffix -form. + This convention helps make it clearer to the macro's user + which parameters are Lisp forms to be evaluated, and which are not. +

    +

    + You should follow the so-called CALL-WITH style when it applies. + This style is explained at length in + http://random-state.net/log/3390120648.html. + The general principle is that the macro is strictly limited to processing the syntax, + and as much of the semantics as possible is kept in normal functions. + Therefore, a macro WITH-FOO is often limited to + generating a call to an auxiliary function + CALL-WITH-FOO + with arguments deduced from the macro arguments. + Macro &body arguments are typically + wrapped into a lambda expression of which they become the body, + which is passed as one of the arguments of the auxiliary function. +

    +

    + The separation of syntactic and semantic concerns + is a general principle of style that applies + beyond the case of WITH- macros. + Its advantages are many. + By keeping semantics outside the macro, + the macro is made simpler, easier to get right, and less subject to change, + which makes it easier to develop and maintain. + The semantics is written in a simpler language — one without staging — + which also makes it easier to develop and maintain. + It becomes possible to debug and update the semantic function + without having to recompile all clients of the macro. + The semantic function appears in the stack trace + which also helps debug client functions. + The macro expansion is made shorter and + each expansion shares more code with other expansions, + which reduces memory pressure which in turn usually makes things faster. + It also makes sense to write the semantic functions first, + and write the macros last as syntactic sugar on top. + You should use this style unless the macro is used + in tight loops where performance matters; + and even then, see our rules regarding optimization. +

    +

    + Any functions (closures) created by the macro should be named, + which can be done using FLET. + + This also allows you to declare the function to be of dynamic extent + (if it is — and often it is; yet see below regarding + DYNAMIC-EXTENT). +

    +

    + If a macro call contains a form, + and the macro expansion includes more than one copy of that form, + the form can be evaluated more than once, + and code it contains macro-expanded and compiled more than once. + If someone uses the macro and calls it + with a form that has side effects or that takes a long time to compute, + the behavior will be undesirable + (unless you're intentionally writing + a control structure such as a loop). + A convenient way to avoid this problem + is to evaluate the form only once, + and bind a (generated) variable to the result. + There is a very useful macro called ALEXANDRIA:ONCE-ONLY + that generates code to do this. + See also ALEXANDRIA:WITH-GENSYMS, + to make some temporary variables in the generated code. + 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; + you therefore avoid the above complexity. +

    +

    + When you write a macro with a body, + such as a WITH-xxx macro, + even if there aren't any parameters, + you should leave space for them anyway. + For example, if you invent WITH-LIGHTS-ON, + do not make the call to it look like + (defmacro with-lights-on (&body b) ...). + Instead, do (defmacro with-lights-on (() &body b) ...). + That way, if parameters are needed in the future, + you can add them without necessarily having to change + all the uses of the macro. +

    + +
    + + + When using EVAL-WHEN, you should almost always use all of + (:compile-toplevel :load-toplevel :execute). + + +

    + Lisp evaluation happens at several times, + some of them interleaved. + Be aware of them when writing macros. + EVAL-WHEN considered harmful to your mental health. +

    +

    + In summary of the article linked above, + unless you're doing truly advanced macrology, + the only valid combination in an EVAL-WHEN + is to include all of + (eval-when (:compile-toplevel :load-toplevel :execute) ...) +

    +

    + You must use + (eval-when (:compile-toplevel :load-toplevel :execute) ...) + whenever you define functions, types, classes, constants, variables, etc., + that are going to be used in macros. +

    +

    + It is usually an error to omit the :execute, + because it prevents LOADing the source rather than the fasl. + It is usually an error to omit the :load-toplevel + (except to modify e.g. readtables and compile-time settings), + because it prevents LOADing future files + or interactively compiling code + that depends on the effects that happen at compile-time, + unless the current file was COMPILE-FILEd + within the same Lisp session. +

    +

    + Regarding variables, note that because macros may or may not + be expanded in the same process that runs the expanded code, + you must not depend on compile-time and runtime effects + being either visible or invisible at the other time. + There are still valid uses of variables in macros: +

    +
      +
    • + Some variables may hold dictionaries + for some new kind of definition and other meta-data. + If such meta-data is to be visible at runtime and/or in other files, + you must make sure that the macro expands into code that + will register the definitions to those meta-data structures + at load-time, + in addition to effecting the registration at compile-time. + Typically, your top-level definitions expand + to code that does the registration. + if your code doesn't expand at the top-level, + you can sometimes use LOAD-TIME-VALUE for good effect. + In extreme cases, you may have to use + ASDF-FINALIZERS:EVAL-AT-TOPLEVEL. +
    • +
    • + Some variables may hold temporary data + that is only used at compile-time in the same file, + and can be cleaned up at the end of the file's compilation. + Predefined such variables would include *readtable* + or compiler-internal variables holding + the current optimization settings. + You can often manage existing and new such variables using + the :AROUND-COMPILE hooks of ASDF. +
    • +
    + +
    + + + You should use #. sparingly, + and you must avoid read-time side-effects. + + +

    + The #. standard read-macro + will read one object, evaluate the object, and + have the reader return the resulting value. +

    +

    + You must not use it where other idioms will do, such as + using EVAL-WHEN to evaluate side-effects at compile-time, + using a regular macro to return an expression computed at compile-time, + using LOAD-TIME-VALUE to compute it at load-time. +

    +

    + Read-time evaluation is often used as a quick way + to get something evaluated at compile time + (actually "read time" but it amounts to the same thing). + If you use this, the evaluation MUST NOT have any side effects + and MUST NOT depend on any variable global state. + The #. should be treated as a way + to force "constant-folding" + that a sufficiently-clever compiler + could have figure out all by itself, + when the compiler isn't sufficiently-clever + and the difference matters. +

    +

    + Another use of #. is to expand the equivalent of macros + in places that are neither expressions nor (quasi)quotations, + such as lambda-lists. However, if you find yourself using it a lot, + it might be time to instead define macros to replace your consumers + of lambda-lists with something that recognizes an extension. +

    +

    + Whenever you are going to use #., + you should consider using DEFCONSTANT and its variants, + possibly in an EVAL-WHEN, + to give the value a name explaining what it means. +

    + +
    + + + You must not use EVAL at runtime. + + +

    + Places where it is actually appropriate to use EVAL + are so few and far between that you must consult with your reviewers; + it's easily misused. +

    +

    + If your code manipulates symbols at runtime + and needs to get the value of a symbol, + use SYMBOL-VALUE, not EVAL. +

    +

    + Often, what you really need is to write a macro, + not to use EVAL. +

    +

    + You may be tempted to use EVAL as a shortcut + to evaluating expressions in a safe subset of the language. + But it often requires more scrutiny to properly check and sanitize + all possible inputs to such use of EVAL + than to build a special-purpose evaluator. + You must not use EVAL in this way at runtime. +

    +

    + Places where it is OK to use EVAL are: +

    +
      +
    • + Implementing an interactive development loop. +
    • +
    • + The build infrastructure. +
    • +
    • + Backdoors that are part of testing frameworks. + (You MUST NOT have such backdoors in production code.) +
    • +
    • + Macros that fold constants at compile-time. +
    • +
    • + Macros that register definitions to meta-data structures; + the registration form is sometimes evaluated at compile-time + as well as included in the macro-expansion, + so it is immediately available to other macros. +
    • +
    +

    + Note that in the latter case, + if the macro isn't going to be used at the top-level, + it might not be possible to make these definitions available + as part of the expansion. + The same phenomenon may happen in a DEFTYPE expansion, + or in helper functions used by macros. + In these cases, you may actually have to use + ASDF-FINALIZERS:EVAL-AT-TOPLEVEL in your macro. + It will not only EVAL your definitions + at macro-expansion time for immediate availability, + it will also save the form aside, for inclusion in a + (ASDF-FINALIZERS:FINAL-FORMS) + that you need to include at the end of the file being compiled + (or before the form is needed). + This way, the side-effects are present when loading the fasl + without having compiled it as well as while compiling it; + in either case, the form is made available at load-time. + ASDF-FINALIZERS ensures that the form is present, + by throwing an error if you omit it. +

    + +
    +
    + @@ -2290,6 +2499,13 @@ Robert Brown If you do use NIL, you must make sure that the distinction is well documented.

    +

    + In many contexts, + instead of representing "I don't know" as a particular value, + you should instead use multiple values, + one for the value that is known if any, + and one to denote whether the value was known or found. +

    When working with database classes, keep in mind that @@ -2301,37 +2517,62 @@ Robert Brown

    - You should select proper data representation. - You should not abuse the LIST data structure. + You must select proper data representation. + You must not abuse the LIST data structure.

    - Common Lisp makes it especially easy to use - its builtin (single-linked) LIST data structure. - However, you should only use this data structure - where it is appropriate. + Even though back in 1958, LISP was short for "LISt Processing", + its successor Common Lisp has been a modern programming language + with modern data structures since the 1980s. + You must use the proper data structures in your programs.

    - You must not use lists - when they are an inappropriate abstraction - for the data being manipulated. + You must not abuse the builtin (single-linked) LIST + data structure where it is not appropriate, + even though Common Lisp makes it especially easy to use it.

    You must only use lists when their performance characteristics - is appropriate for the algorithm at hand - (i.e. sequential iteration over the entire contents). + is appropriate for the algorithm at hand: + sequential iteration over the entire contents of the list.

    - An exception is when it is known in advance + An exception where it is appropriate to use lists + is when it is known in advance that the size of the list will remain very short - (say, less than 16 elements), - especially so when manipulating source code at compile-time. + (say, less than 16 elements).

    - Another exception is for introducing literal constants + List data structures are often (but not always) + appropriate for macros and functions used by macros at compile-time: + indeed, not only is source code passed as lists in Common Lisp, + but the macro-expansion and compilation processes + will typically walk over the entire source code, sequentially, once. + (Note that advanced macro systems don't directly use lists, but instead + use abstract syntax objects that track source code location and scope; + however there is no such advanced macro system + in Common Lisp at this time.) +

    +

    + Another exception where it is appropriate to use lists is + for introducing literal constants that will be transformed into more appropriate data structures at compile-time or load-time. + It is a good to have a function with a relatively short name + to build your program's data structures from such literals. +

    +

    + In the many cases when lists are not the appropriate data structure, + various libraries such as + cl-containers or + lisp-interface-library + provide plenty of different data structures + that should fulfill all the basic needs of your programs. + If the existing libraries are not satisfactory, see above about + Using Libraries and + Open-Sourcing Code.

    @@ -2460,12 +2701,14 @@ Robert Brown - You should usually refer to a function as #'FUN rather than 'FUN. + You should usually refer to a function as #'FOO rather than 'FOO.

    - The former refers to the function object, as is properly scoped. - The latter refers to the symbol, which when called + 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.

    @@ -2508,7 +2751,8 @@ Robert Brown

    Note that if you start writing a new system in a heavily functional style, - you may consider using LAMBDA-READER, + 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 @@ -2516,55 +2760,6 @@ Robert Brown

    - - - Common Lisp pathnames are tricky. Be aware of pitfalls. - - -

    - It is surprisingly hard to properly deal with pathnames in Common Lisp. -

    -

    - First, be aware of the discrepancies between - the syntax of Common Lisp pathnames, - which depends on which implementation and operating system - you are using, - and the native syntax of pathnames on your operating system. - The Lisp syntax may involves quoting of special characters - such as #\. and #\*, etc., - in addition to the quoting of - #\\ and #\" within strings. - By contrast, your operating system's other - system programming languages - (shell, C, scripting languages) - may only have one layer of quoting, into strings. -

    -

    - Second, when using MERGE-PATHNAMES, - be wary of the treatment of the HOST component, - which matters a lot on non-Unix platforms. - You probably should instead be using - ASDF-UTILS:MERGE-PATHNAMES*. -

    -

    - Third, be aware that DIRECTORY is not portable - in how it handles wildcards, sub-directories, symlinks, etc. - There again, ASDF-UTILS provides several - common abstractions to deal with pathnames. -

    -

    - Finally, be aware that paths may change between - the time you build the Lisp image for your application, - and the time you run the application from its image. - You should be careful to reset your image - to forget irrelevant build-time paths and - reinitialize any search path from current environment variables. - ASDF for instance requires you to reset its paths - with ASDF:CLEAR-CONFIGURATION. -

    - - -
    @@ -2651,15 +2846,23 @@ Robert Brown If you are implementing a method of a generic function, and it does not need to know the values of some of the keyword arguments, - it is acceptable to use &ALLOW-OTHER-KEYS - rather than list all the keyword arguments explicitly - and use (declare (ignore ...)) on them. - (Of course in such a case there should not be a &REST.) + you should explicitly (DECLARE (IGNORE ...)) + all the arguments that you are not using. + You must not use &ALLOW-OTHER-KEYS + unless you explicitly want to disable checking of allowed keys + for all methods when invoking the generic function on arguments + that match this particular method. Note that the contract of a generic function belongs in the DEFGENERIC, not in the DEFMETHOD which is basically an "implementation detail" of the generic function as far as the caller of the generic is concerned.

    +

    + A case where &ALLOW-OTHER-KEYS is appropriate + is when you write a wrapper function to other some other functions + that may vary (within the computation or during development), + and pass around a plist as a &REST argument. +

    You should avoid using &AUX arguments, except in very short helper functions @@ -2675,6 +2878,17 @@ Robert Brown when your function has both &OPTIONAL and &KEY arguments.

    +

    + For maximum portability of a library, it is good form + that DEFMETHOD definitions should + (DECLARE (IGNORABLE ...)) + all the required arguments that they are not using. + Indeed, some implementations will issue a warning + if you (DECLARE (IGNORE ...)) those arguments, + whereas other implementations will issue a warning + if you fail to (DECLARE (IGNORE ...)) them. + (DECLARE (IGNORABLE ...)) works on all implementations. +

    You should avoid excessive nesting of binding forms inside a function. If your function ends up with massive nesting, @@ -2714,6 +2928,15 @@ Robert Brown to explicitly return NIL if you have a specific reason to insist on the return value.

    +

    + You should prefer AND and OR + when it leads to more concise code than using + IF, COND, + WHEN or UNLESS, + and there are no side-effects involved. + You may also use an ERROR + as a side-effect in the final clause of an OR. +

    You should only use CASE and ECASE to compare numbers, characters or symbols @@ -2814,9 +3037,12 @@ Robert Brown performance-critical low-level code. EQL reduces the opportunity for a class of embarrassing errors - (i.e. if characters are ever compared). + (i.e. if numbers or characters are ever compared). There may a tiny performance cost relative to EQ, although under SBCL, it often compiles away entirely. + EQ is equivalent to EQL and type declarations, + and use of it for optimization should be treated just like + any such unsafe operations.

    You should use CHAR= @@ -2877,8 +3103,8 @@ Robert Brown of floating-point arithmetic. Libraries such as wu-decimal - can help you; - if this library is not satisfactory, see above about + may help you; + once again, if this library is not satisfactory, see above about Using Libraries and Open-Sourcing Code.

    @@ -3049,44 +3275,6 @@ Robert Brown - - - You should not use EVAL. - - -

    - Places where it is actually appropriate to use EVAL - are so few and far between that you must consult with your reviewers; - it's easily misused. -

    -

    - If your code manipulates symbols at runtime - and needs to get the value of a symbol, - use SYMBOL-VALUE, not EVAL. -

    -

    - Often, what you really need is to write a macro, - not to use EVAL. -

    -

    - Places where it is OK to use EVAL are: - testing frameworks and code that is ONLY used for testing; - the build infrastructure; and - inside macros when there isn't any reasonable way - to avoid using EVAL - (there almost always is, and where there isn't, - consider that unless you can also dump - code to reproduce the side-effects being evaluated - in the macro expansion, - you may actually have to use - ASDF-FINALIZERS:EVAL-AT-TOPLEVEL - so the side-effects are present when loading the fasl - without compiling). - Other uses need to be checked. - We do have a few special cases where EVAL is allowed. -

    - -
    @@ -3121,7 +3309,79 @@ Robert Brown

    - + + + You must only use faster unsafe operations + when there is a clear performance need + and you can document why it's correct. + + +

    + Common Lisp implementations often provide backdoors + to compute some operations faster in an unsafe way. + For instance, some libraries provide arithmetic operations + that are designed to be used with fixnums only, + and yield the correct result faster if provided proper arguments. + The downside is that the result of such operations + is incorrect in case of overflow, and can + have undefined behavior when called with anything but fixnums. +

    + +

    + More generally, unsafe operations + will yield the correct result faster + than would the equivalent safe operation + if the arguments to satisfy some invariant such as + being of the correct type and small enough; + however if the arguments fail to satisfy the required invariants, + then the operation may have undefined behavior, + such as crashing the software, or, + which is sometimes worse, silently giving wrong answers. + Depending on whether the software is piloting an aircraft + or other life-critical device, + or whether it is accounting for large amounts money, + such undefined behavior can kill or bankrupt people. + Yet proper speed can sometimes make the difference between + software that's unusably slow and software that does its job; + between software that is a net loss + and software that can yield a profit. +

    +

    + You must not define or use unsafe operations without both + profiling results indicating the need for this optimization, + and careful documentation explaining why it is safe to use them. + Unsafe operations should be restricted to internal functions; + you should carefully documented how unsafe it is + to use these functions with the wrong arguments. + You should only use unsafe operations + inside functions internal to a package and + you should document the use of the declarations, + since calling the functions with arguments of the wrong type + can lead to undefined behavior. + Use check-type in functions exported from a package + to sanitize input arguments, + so that internal functions are never passed illegal values. +

    +

    + On some compilers, + new unsafe operations + can usually be defined by combining + type declarations with an OPTIMIZE declaration + that has sufficiently high SPEED and low SAFETY. + In addition to providing more speed for production code, + such declarations may more helpful + than check-type assertions + for finding bugs at compile-time, + on compilers that have type inference. + These compilers may interpret those declarations as assertions + if you switch to safer and slower optimize settings; + this is good to locate a dynamic error in your code during development, + but is not to be used for production code since + it defeats the purpose of declarations as a performance trick. +

    + +
    + You should only use DYNAMIC-EXTENT where it matters for performance, @@ -3129,6 +3389,9 @@ Robert Brown

    + DYNAMIC-EXTENT declaration are + a particular case of + unsafe operations.

    The purpose of the DYNAMIC-EXTENT declaration @@ -3225,78 +3488,6 @@ Robert Brown

    - - - You must only use faster unsafe operations - when there is a clear performance need - and you can document why it's correct. - - -

    - Common Lisp implementations often provide backdoors - to compute some operations faster in an unsafe way. - For instance, some libraries provide arithmetic operations - that are designed to be used with fixnums only, - and yield the correct result faster if provided proper arguments. - The downside is that the result of such operations - is incorrect in case of overflow, and can - have undefined behavior when called with anything but fixnums. -

    - -

    - More generally, unsafe operations - will yield the correct result faster - than would the equivalent safe operation - if the arguments to satisfy some invariant such as - being of the correct type and small enough; - however if the arguments fail to satisfy the required invariants, - then the operation may have undefined behavior, - such as crashing the software, or, - which is sometimes worse, silently giving wrong answers. - Depending on whether the software is piloting an aircraft - or other life-critical device, - or whether it is accounting for large amounts money, - such undefined behavior can kill or bankrupt people. - Yet proper speed can sometimes make the difference between - software that's unusably slow and software that does its job; - between software that is a net loss - and software that can yield a profit. -

    -

    - You must not define or use unsafe operations without both - profiling results indicating the need for this optimization, - and careful documentation explaining why it is safe to use them. - Unsafe operations should be restricted to internal functions; - you should carefully documented how unsafe it is - to use these functions with the wrong arguments. - You should only use unsafe operations - inside functions internal to a package and - you should document the use of the declarations, - since calling the functions with arguments of the wrong type - can lead to undefined behavior. - Use check-type in functions exported from a package - to sanitize input arguments, - so that internal functions are never passed illegal values. -

    -

    - On some compilers, - new unsafe operations - can usually be defined by combining - type declarations with an OPTIMIZE declaration - that has sufficiently high SPEED and low SAFETY. - In addition to providing more speed for production code, - such declarations may more helpful - than check-type assertions - for finding bugs at compile-time, - on compilers that have type inference. - These compilers may interpret those declarations as assertions - if you switch to safer and slower optimize settings; - this is good to locate a dynamic error in your code during development, - but is not to be used for production code since - it defeats the purpose of declarations as a performance trick. -

    - -
    You should use REDUCE @@ -3399,6 +3590,81 @@ Robert Brown + + + Common Lisp pathnames are tricky. Be aware of pitfalls. + + +

    + It is surprisingly hard to properly deal with pathnames in Common Lisp. +

    +

    + First, be aware of the discrepancies between + the syntax of Common Lisp pathnames, + which depends on which implementation and operating system + you are using, + and the native syntax of pathnames on your operating system. + The Lisp syntax may involves quoting of special characters + such as #\. and #\*, etc., + in addition to the quoting of + #\\ and #\" within strings. + By contrast, your operating system's other + system programming languages + (shell, C, scripting languages) + may only have one layer of quoting, into strings. +

    +

    + Second, when using MERGE-PATHNAMES, + be wary of the treatment of the HOST component, + which matters a lot on non-Unix platforms + (and even on some Unix implementations). + You probably should be using + ASDF-UTILS:MERGE-PATHNAMES* + instead of MERGE-PATHNAMES, + especially if your expectations for relative pathnames + are informed by the way they work in Unix or Windows; + otherwise you might hit weird bugs whereby on some implementations, + merging a relative pathnames with an absolute pathname + results in overriding the absolute pathname's host + and replace it with the host from the value of + *DEFAULT-PATHNAME-DEFAULTS* + at the time the relative pathname was created. +

    +

    + Third, be aware that DIRECTORY + is not portable across implementations + in how it handles wildcards, sub-directories, symlinks, etc. + There again, ASDF-UTILS provides several + common abstractions to deal with pathnames. +

    +

    + LOGICAL-PATHNAMEs are not a portable abstraction, + and should not be used in portable code. + Many implementations have bugs in them, when they are supported at all. + SBCL implements them very well, + but strictly enforces the limitations on characters + allowed by the standard. + Other implementations allow arbitrary characters in such pathnames, + but in doing so are not being conformant, + and are still incompatible with each other in many ways. + You should use other pathname abstractions, + such as ASDF:SYSTEM-RELATIVE-PATHNAME or + the underlying ASDF-UTILS:COERCE-PATHNAME. +

    + +

    + Finally, be aware that paths may change between + the time you build the Lisp image for your application, + and the time you run the application from its image. + You should be careful to reset your image + to forget irrelevant build-time paths and + reinitialize any search path from current environment variables. + ASDF for instance requires you to reset its paths + with ASDF:CLEAR-CONFIGURATION. +

    + + +
    You must be careful when using a SATISFIES clause in a type specifier. @@ -3442,16 +3708,16 @@ Robert Brown and MUST be defined within an EVAL-WHEN.

    - (defun prime-number-p (n) ;; Doubly BAD! + (defun prime-number-p (n) ; Doubly bad! (let ((m (abs n))) (if (<= m *prime-number-cutoff*) (small-prime-number-p m) (big-prime-number-p m)))) - (eval-when (:compile-toplevel :load-toplevel :execute) ;; Better + (eval-when (:compile-toplevel :load-toplevel :execute) ; Better (defun prime-number-p (n) - (when (integerp n) ;; Better + (when (integerp n) ; Better (let ((m (abs n))) (if (<= m *prime-number-cutoff*) (small-prime-number-p m) @@ -3490,15 +3756,10 @@ Robert Brown Therefore, you cannot merely create the function as a side-effect of expansion using EVAL at type-expansion time. - The solution is to use EVAL-AT-TOPLEVEL - from ASDF-FINALIZERS. - It will not only EVAL your function definition - at type-expansion time for immediate availability, - it will also save the form aside, for inclusion in a - (FINAL-FORMS) at the end of the file being compiled, - which ASDF-FINALIZERS ensures you include, - throwing an error if you omit it. - This way, the form is also available at load-time. + The solution is to use + ASDF-FINALIZERS:EVAL-AT-TOPLEVEL instead. + See the very last point + in the discussion about EVAL.

    Common Lisp is hard to satisfy. @@ -3519,7 +3780,7 @@ Robert Brown

    -Revision 1.11 +Revision 1.12