Merge branch 'google:gh-pages' into gh-pages

This commit is contained in:
Tien Nguyen Minh 2024-02-29 16:34:12 +07:00 committed by GitHub
commit 888f2a9bcb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 3779 additions and 2048 deletions

View File

@ -21,8 +21,8 @@ this power brings with it complexity, which in turn can make
code more bug-prone and harder to read and maintain.</p> code more bug-prone and harder to read and maintain.</p>
<p>The goal of this guide is to manage this complexity by <p>The goal of this guide is to manage this complexity by
describing in detail the dos and don'ts of writing C++ code describing in detail the dos and don'ts of writing C++
. These rules exist to code. These rules exist to
keep the code base manageable while still allowing keep the code base manageable while still allowing
coders to use C++ language features productively.</p> coders to use C++ language features productively.</p>
@ -164,9 +164,8 @@ input.</p>
<h2 id="C++_Version">C++ Version</h2> <h2 id="C++_Version">C++ Version</h2>
<p>Currently, code should target C++17, i.e., should not use C++2x <p>Currently, code should target C++20, i.e., should not use C++23
features, with the exception of <a href="#Designated_initializers">designated features. The C++ version targeted by this guide will advance
initializers</a>. The C++ version targeted by this guide will advance
(aggressively) over time.</p> (aggressively) over time.</p>
@ -176,7 +175,7 @@ input.</p>
<div> <div>
<p>Consider portability to other environments before using features <p>Consider portability to other environments before using features
from C++14 and C++17 in your project.</p> from C++17 and C++20 in your project.</p>
</div> </div>
<h2 id="Header_Files">Header Files</h2> <h2 id="Header_Files">Header Files</h2>
@ -415,6 +414,18 @@ should be included as:</p>
<pre>#include "base/logging.h" <pre>#include "base/logging.h"
</pre> </pre>
<p>Headers should only be included using an angle-bracketed path if the library
requires you to do so. In particular, the following headers require angle
brackets:</p>
<ul>
<li>C and C++ standard library headers (e.g. <code>&lt;stdlib.h&gt;</code>
and <code>&lt;string&gt;</code>).</li>
<li>POSIX, Linux, and Windows system headers (e.g. <code>&lt;unistd.h&gt;</code>
and <code>&lt;windows.h&gt;</code>).</li>
<li>In rare cases, third_party libraries (e.g. <code>&lt;Python.h&gt;</code>).</li>
</ul>
<p>In <code><var>dir/foo</var>.cc</code> or <p>In <code><var>dir/foo</var>.cc</code> or
<code><var>dir/foo_test</var>.cc</code>, whose main <code><var>dir/foo_test</var>.cc</code>, whose main
purpose is to implement or test the stuff in purpose is to implement or test the stuff in
@ -426,9 +437,9 @@ as follows:</p>
<li>A blank line</li> <li>A blank line</li>
<li>C system headers (more precisely: headers in angle brackets with the <li>C system headers, and any other headers in angle brackets with the
<code>.h</code> extension), e.g., <code>&lt;unistd.h&gt;</code>, <code>.h</code> extension, e.g., <code>&lt;unistd.h&gt;</code>,
<code>&lt;stdlib.h&gt;</code>.</li> <code>&lt;stdlib.h&gt;</code>, <code>&lt;Python.h&gt;</code>.</li>
<li>A blank line</li> <li>A blank line</li>
@ -664,9 +675,9 @@ namespace baz = ::foo::bar::baz;
<pre>// Shorten access to some commonly used names (in a .h file). <pre>// Shorten access to some commonly used names (in a .h file).
namespace librarian { namespace librarian {
namespace impl { // Internal, not part of the API. namespace internal { // Internal, not part of the API.
namespace sidetable = ::pipeline_diagnostics::sidetable; namespace sidetable = ::pipeline_diagnostics::sidetable;
} // namespace impl } // namespace internal
inline void my_inline_function() { inline void my_inline_function() {
// namespace alias local to a function (or method). // namespace alias local to a function (or method).
@ -686,6 +697,11 @@ inline void my_inline_function() {
using ::absl::container_internal::ImplementationDetail; using ::absl::container_internal::ImplementationDetail;
</pre> </pre>
</li> </li>
<li><p>Single-line nested namespace declarations
are preferred in new code, but are not required.</p>
</li>
</ul> </ul>
<a id="Unnamed_Namespaces_and_Static_Variables"></a> <a id="Unnamed_Namespaces_and_Static_Variables"></a>
@ -932,7 +948,7 @@ the formal language of the C++ standard. It means that the initializing
expression is a constant expression, and if the object is initialized by a expression is a constant expression, and if the object is initialized by a
constructor call, then the constructor must be specified as constructor call, then the constructor must be specified as
<code>constexpr</code>, too:</p> <code>constexpr</code>, too:</p>
<pre>struct Foo { constexpr Foo(int) {} }; <pre class="goodcode">struct Foo { constexpr Foo(int) {} };
int n = 5; // Fine, 5 is a constant expression. int n = 5; // Fine, 5 is a constant expression.
Foo x(2); // Fine, 2 is a constant expression and the chosen constructor is constexpr. Foo x(2); // Fine, 2 is a constant expression and the chosen constructor is constexpr.
@ -940,12 +956,8 @@ Foo a[] = { Foo(1), Foo(2), Foo(3) }; // Fine</pre>
<p>Constant initialization is always allowed. Constant initialization of <p>Constant initialization is always allowed. Constant initialization of
static storage duration variables should be marked with <code>constexpr</code> static storage duration variables should be marked with <code>constexpr</code>
or where possible the or <code>constinit</code>.
Any non-local static storage
<a href="https://github.com/abseil/abseil-cpp/blob/03c1513538584f4a04d666be5eb469e3979febba/absl/base/attributes.h#L540">
<code>ABSL_CONST_INIT</code></a>
attribute. Any non-local static storage
duration variable that is not so marked should be presumed to have duration variable that is not so marked should be presumed to have
dynamic initialization, and reviewed very carefully.</p> dynamic initialization, and reviewed very carefully.</p>
@ -1017,10 +1029,8 @@ does not make an observable difference. For example:</p>
<p><code>thread_local</code> variables that aren't declared inside a function <p><code>thread_local</code> variables that aren't declared inside a function
must be initialized with a true compile-time constant, must be initialized with a true compile-time constant,
and this must be enforced by using the and this must be enforced by using the
<a href="https://en.cppreference.com/w/cpp/language/constinit">
<code>constinit</code></a>
<a href="https://github.com/abseil/abseil-cpp/blob/master/absl/base/attributes.h">
<code>ABSL_CONST_INIT</code></a>
attribute. Prefer attribute. Prefer
<code>thread_local</code> over other ways of defining thread-local data.</p> <code>thread_local</code> over other ways of defining thread-local data.</p>
@ -1093,13 +1103,11 @@ get a particularly hard to diagnose use-after-free.</p>
initialized with a true compile-time constant (i.e., they must have no initialized with a true compile-time constant (i.e., they must have no
dynamic initialization). To enforce this, <code>thread_local</code> variables dynamic initialization). To enforce this, <code>thread_local</code> variables
at class or namespace scope must be annotated with at class or namespace scope must be annotated with
<a href="https://en.cppreference.com/w/cpp/language/constinit">
<code>constinit</code></a>
<a href="https://github.com/abseil/abseil-cpp/blob/master/absl/base/attributes.h">
<code>ABSL_CONST_INIT</code></a>
(or <code>constexpr</code>, but that should be rare):</p> (or <code>constexpr</code>, but that should be rare):</p>
<pre> ABSL_CONST_INIT thread_local Foo foo = ...; <pre> constinit thread_local Foo foo = ...;
</pre> </pre>
<p><code>thread_local</code> variables inside a function have no initialization <p><code>thread_local</code> variables inside a function have no initialization
@ -1177,8 +1185,7 @@ for your code ,
terminating the program may be an appropriate error handling terminating the program may be an appropriate error handling
response. Otherwise, consider a factory function response. Otherwise, consider a factory function
or <code>Init()</code> method as described in or <code>Init()</code> method as described in
<a href="https://abseil.io/tips/42">TotW #42</a> <a href="https://abseil.io/tips/42">TotW #42</a>.
.
Avoid <code>Init()</code> methods on objects with Avoid <code>Init()</code> methods on objects with
no other states that affect which public methods may be called no other states that affect which public methods may be called
(semi-constructed objects of this form are particularly hard to work (semi-constructed objects of this form are particularly hard to work
@ -1445,8 +1452,6 @@ by making their constructors protected, by declaring their destructors protected
or by giving them one or more pure virtual member functions. Prefer to avoid or by giving them one or more pure virtual member functions. Prefer to avoid
deriving from concrete classes.</p> deriving from concrete classes.</p>
<h3 id="Structs_vs._Classes">Structs vs. Classes</h3> <h3 id="Structs_vs._Classes">Structs vs. Classes</h3>
<p>Use a <code>struct</code> only for passive objects that <p>Use a <code>struct</code> only for passive objects that
@ -1466,9 +1471,9 @@ break those invariants. Constructors, destructors, and helper methods may
be present; however, these methods must not require or enforce any be present; however, these methods must not require or enforce any
invariants.</p> invariants.</p>
<p>If more functionality or invariants are required, a <p>If more functionality or invariants are required, or struct has wide visibility and expected to
<code>class</code> is more appropriate. If in doubt, make evolve, then a <code>class</code> is more appropriate. If in doubt, make it a <code>class</code>.
it a <code>class</code>.</p> </p>
<p>For consistency with STL, you can use <p>For consistency with STL, you can use
<code>struct</code> instead of <code>class</code> for <code>struct</code> instead of <code>class</code> for
@ -1678,17 +1683,23 @@ definitions. If possible, avoid defining operators as templates,
because they must satisfy this rule for any possible template because they must satisfy this rule for any possible template
arguments. If you define an operator, also define arguments. If you define an operator, also define
any related operators that make sense, and make sure they any related operators that make sense, and make sure they
are defined consistently. For example, if you overload are defined consistently.</p>
<code>&lt;</code>, overload all the comparison operators,
and make sure <code>&lt;</code> and <code>&gt;</code> never
return true for the same arguments.</p>
<p>Prefer to define non-modifying binary operators as <p>Prefer to define non-modifying binary operators as
non-member functions. If a binary operator is defined as a non-member functions. If a binary operator is defined as a
class member, implicit conversions will apply to the class member, implicit conversions will apply to the
right-hand argument, but not the left-hand one. It will right-hand argument, but not the left-hand one. It will
confuse your users if <code>a &lt; b</code> compiles but confuse your users if <code>a + b</code> compiles but
<code>b &lt; a</code> doesn't.</p> <code>b + a</code> doesn't.</p>
<p>For a type <code>T</code> whose values can be compared for
equality, define a non-member <code>operator==</code> and document when
two values of type <code>T</code> are considered equal.
If there is a single obvious notion of when a value <code>t1</code>
of type <code>T</code> is less than another such value <code>t2</code> then
you may also define <code>operator&lt;=&gt;</code>, which should be
consistent with <code>operator==</code>.
Prefer not to overload the other comparison and ordering operators.</p>
<p>Don't go out of your way to avoid defining operator <p>Don't go out of your way to avoid defining operator
overloads. For example, prefer to define <code>==</code>, overloads. For example, prefer to define <code>==</code>,
@ -1788,7 +1799,7 @@ improve readability, and often provide the same or better
performance.</p> performance.</p>
<p>Prefer to return by value or, failing that, return by reference. <p>Prefer to return by value or, failing that, return by reference.
Avoid returning a pointer unless it can be null.</p> Avoid returning a raw pointer unless it can be null.</p>
<p>Parameters are either inputs to the function, outputs from the <p>Parameters are either inputs to the function, outputs from the
function, or both. Non-optional input parameters should usually be values function, or both. Non-optional input parameters should usually be values
@ -1802,10 +1813,10 @@ optional outputs and optional input/output parameters.</p>
<p> <p>
Avoid defining functions that require a <code>const</code> reference parameter Avoid defining functions that require a reference parameter to outlive the call.
to outlive the call, because <code>const</code> reference parameters bind In some cases reference parameters can bind to temporaries, leading to lifetime
to temporaries. Instead, find a way to eliminate the lifetime requirement bugs. Instead, find a way to eliminate the lifetime requirement
(for example, by copying the parameter), or pass it by <code>const</code> (for example, by copying the parameter), or pass retained parameters by
pointer and document the lifetime and non-null requirements. pointer and document the lifetime and non-null requirements.
</p> </p>
@ -2249,10 +2260,10 @@ qualifier to methods), except as follows:</p>
<li>You may use them to define pairs of overloads, such as one taking <li>You may use them to define pairs of overloads, such as one taking
<code>Foo&amp;&amp;</code> and the other taking <code>const Foo&amp;</code>. <code>Foo&amp;&amp;</code> and the other taking <code>const Foo&amp;</code>.
Usually the preferred solution is just to pass by value, but an overloaded Usually the preferred solution is just to pass by value, but an overloaded
pair of functions sometimes yields better performance and is sometimes pair of functions sometimes yields better performance, for example if the
necessary in generic code that needs to support a wide variety of types. functions sometimes don't consume the input. As always: if you're writing
As always: if you're writing more complicated code for the sake of more complicated code for the sake of performance, make sure you have evidence
performance, make sure you have evidence that it actually helps.</li> that it actually helps.</li>
</ul> </ul>
<h3 id="Friends">Friends</h3> <h3 id="Friends">Friends</h3>
@ -2636,9 +2647,9 @@ casts when explicit type conversion is necessary.
including <code>void*</code>. Use this including <code>void*</code>. Use this
only if you know what you are doing and you understand the aliasing only if you know what you are doing and you understand the aliasing
issues. Also, consider dereferencing the pointer (without a cast) and issues. Also, consider dereferencing the pointer (without a cast) and
using <code>absl::bit_cast</code> to cast the resulting value.</li> using <code>std::bit_cast</code> to cast the resulting value.</li>
<li>Use <code>absl::bit_cast</code> to interpret the raw bits of a <li>Use <code>std::bit_cast</code> to interpret the raw bits of a
value using a different type of the same size (a type pun), such as value using a different type of the same size (a type pun), such as
interpreting the bits of a <code>double</code> as interpreting the bits of a <code>double</code> as
<code>int64_t</code>.</li> <code>int64_t</code>.</li>
@ -2874,10 +2885,13 @@ putting the "adjective" (<code>const</code>) before the
<code>const</code> first, we do not require it. But be <code>const</code> first, we do not require it. But be
consistent with the code around you!</p> consistent with the code around you!</p>
<h3 id="Use_of_constexpr">Use of constexpr</h3> <h3 id="Use_of_constexpr">Use of constexpr, constinit, and consteval</h3>
<p>Use <code>constexpr</code> to define true <p>Use <code>constexpr</code> to define true
constants or to ensure constant initialization.</p> constants or to ensure constant initialization.
Use <code>constinit</code> to ensure constant
initialization for non-constant variables.
</p>
<p class="definition"></p> <p class="definition"></p>
<p> Some variables can be declared <code>constexpr</code> <p> Some variables can be declared <code>constexpr</code>
@ -2885,7 +2899,8 @@ to indicate the variables are true constants, i.e., fixed at
compilation/link time. Some functions and constructors compilation/link time. Some functions and constructors
can be declared <code>constexpr</code> which enables them can be declared <code>constexpr</code> which enables them
to be used in defining a <code>constexpr</code> to be used in defining a <code>constexpr</code>
variable.</p> variable. Functions can be declared <code>consteval</code>
to restrict their use to compile time.</p>
<p class="pros"></p> <p class="pros"></p>
<p>Use of <code>constexpr</code> enables definition of <p>Use of <code>constexpr</code> enables definition of
@ -2906,9 +2921,11 @@ in these definitions.</p>
robust specification of the constant parts of an robust specification of the constant parts of an
interface. Use <code>constexpr</code> to specify true interface. Use <code>constexpr</code> to specify true
constants and the functions that support their constants and the functions that support their
definitions. Avoid complexifying function definitions to definitions. <code>consteval</code> may be used for
code that must not be invoked at runtime.
Avoid complexifying function definitions to
enable their use with <code>constexpr</code>. Do not use enable their use with <code>constexpr</code>. Do not use
<code>constexpr</code> to force inlining.</p> <code>constexpr</code> or <code>consteval</code> to force inlining.</p>
<h3 id="Integer_Types">Integer Types</h3> <h3 id="Integer_Types">Integer Types</h3>
@ -2948,7 +2965,9 @@ like <code>int16_t</code>, <code>uint32_t</code>,
<code>int64_t</code>, etc. You should always use <code>int64_t</code>, etc. You should always use
those in preference to <code>short</code>, <code>unsigned those in preference to <code>short</code>, <code>unsigned
long long</code> and the like, when you need a guarantee long long</code> and the like, when you need a guarantee
on the size of an integer. Of the built-in integer types, only on the size of an integer. Prefer to omit the <code>std::</code>
prefix for these types, as the extra 5 characters do
not merit the added clutter. Of the built-in integer types, only
<code>int</code> should be used. When appropriate, you <code>int</code> should be used. When appropriate, you
are welcome to use standard type aliases like are welcome to use standard type aliases like
<code>size_t</code> and <code>ptrdiff_t</code>.</p> <code>size_t</code> and <code>ptrdiff_t</code>.</p>
@ -3148,7 +3167,6 @@ possible:</p>
<li>Prefer not using <code>##</code> to generate <li>Prefer not using <code>##</code> to generate
function/class/variable names.</li> function/class/variable names.</li>
</ul> </ul>
<p>Exporting macros from headers (i.e., defining them in a header <p>Exporting macros from headers (i.e., defining them in a header
@ -3230,8 +3248,8 @@ auto c = b; // c is an int
auto d{42}; // d is an int, not a std::initializer_list&lt;int&gt; auto d{42}; // d is an int, not a std::initializer_list&lt;int&gt;
</pre> </pre>
<code>auto</code> can be qualified with <code>const</code>, and can be <code>auto</code> can be qualified with <code>const</code>, and can be
used as part of a pointer or reference type, but it can't be used as a used as part of a pointer or reference type, and (since C++17) as a
template argument. A rare variant of this syntax uses non-type template argument. A rare variant of this syntax uses
<code>decltype(auto)</code> instead of <code>auto</code>, in which case <code>decltype(auto)</code> instead of <code>auto</code>, in which case
the deduced type is the result of applying the deduced type is the result of applying
<a href="https://en.cppreference.com/w/cpp/language/decltype"><code>decltype</code></a> <a href="https://en.cppreference.com/w/cpp/language/decltype"><code>decltype</code></a>
@ -3525,8 +3543,8 @@ ordering of fields than the <code>Point</code> example above.</p>
<p class="cons"></p> <p class="cons"></p>
<p>While designated initializers have long been part of the C standard and <p>While designated initializers have long been part of the C standard and
supported by C++ compilers as an extension, only recently have they made it supported by C++ compilers as an extension, they were not supported by
into the C++ standard, being added as part of C++20.</p> C++ prior to C++20.</p>
<p>The rules in the C++ standard are stricter than in C and compiler extensions, <p>The rules in the C++ standard are stricter than in C and compiler extensions,
requiring that the designated initializers appear in the same order as the requiring that the designated initializers appear in the same order as the
@ -3768,6 +3786,113 @@ error messages are part of your user interface, and your code should
be tweaked as necessary so that the error messages are understandable be tweaked as necessary so that the error messages are understandable
and actionable from a user point of view.</p> and actionable from a user point of view.</p>
<h3 id="Concepts">Concepts and Constraints</h3>
<p>Use concepts sparingly.
In general, concepts and constraints should only be used in cases
where templates would have been used prior to C++20.
Avoid introducing new concepts in headers,
unless the headers are marked as internal to the library.
Do not define concepts that are not enforced by the compiler.
Prefer constraints over template metaprogramming, and
avoid the <code>template&lt;<i>Concept</i> T&gt;</code> syntax;
instead, use the <code>requires(<i>Concept&lt;T&gt;</i>)</code>
syntax.</p>
<p class="definition"></p>
<p>The <code>concept</code> keyword is a new mechanism for defining
requirements (such as type traits or interface specifications)
for a template parameter.
The <code>requires</code> keyword provides mechanisms for placing
anonymous constraints on templates and verifying that constraints
are satisfied at compile time.
Concepts and constraints are often used together, but can be
also used independently.</p>
<p class="pros"></p>
<ul>
<li>Concepts allow the compiler to generate much better error
messages when templates are involved, which can reduce confusion
and significantly improve the development experience.</li>
<li>Concepts can reduce the boilerplate necessary for defining
and using compile-time constraints, often increasing the clarity
of the resulting code.</li>
<li>Constraints provide some capabilities that are difficult to
achieve with templates and SFINAE techniques.</li>
</ul>
<p class="cons"></p>
<ul>
<li>As with templates, concepts can make code significantly more
complex and difficult to understand.</li>
<li>Concept syntax can be confusing to readers, as concepts
appear similar to class types at their usage sites.</li>
<li>Concepts, especially at API boundaries, increase code
coupling, rigidity, and ossification.</li>
<li>Concepts and constraints can replicate logic from a function
body, resulting in code duplication and increased maintenance
costs.</li>
<li>Concepts muddy the source of truth for their underlying
contracts, as they are standalone named entities that can be
utilized in multiple locations, all of which evolve separately
from each other.
This can cause the stated and implied requirements to diverge
over time.</li>
<li>Concepts and constraints affect overload resolution in novel
and non-obvious ways.</li>
<li>As with SFINAE, constraints make it harder to refactor code
at scale.</li>
</ul>
<p class="decision"></p>
<p>Predefined concepts in the standard library should be
preferred to type traits, when equivalent ones exist.
(e.g., if <code>std::is_integral_v</code> would have been used
before C++20, then <code>std::integral</code> should be used in
C++20 code.)
Similarly, prefer modern constraint syntax
(via <code>requires(<i>Condition</i>)</code>).
Avoid legacy template metaprogramming constructs
(such as <code>std::enable_if&lt;<i>Condition</i>&gt;</code>)
as well as the <code>template&lt;<i>Concept</i> T&gt;</code>
syntax.</p>
<p>Do not manually re-implement any existing concepts or traits.
For example, use
<code>requires(std::default_initializable&lt;T&gt;)</code>
instead of
<code>requires(requires { T v; })</code>
or the like.
</p><p>New <code>concept</code> declarations should be rare, and only
defined internally within a library, such that they are not
exposed at API boundaries.
More generally, do not use concepts or constraints in cases where
you wouldn't use their legacy template equivalents in C++17.
</p>
<p>Do not define concepts that duplicate the function body,
or impose requirements that would be insignificant or obvious
from reading the body of the code or the resulting error messages.
For example, avoid the following:
</p><pre class="badcode">template &lt;typename T&gt; // Bad - redundant with negligible benefit
concept Addable = std::copyable&lt;T&gt; &amp;&amp; requires(T a, T b) { a + b; };
template &lt;Addable T&gt;
T Add(T x, T y, T z) { return x + y + z; }
</pre>
Instead, prefer to leave code as an ordinary template unless
you can demonstrate that concepts result in significant
improvement for that particular case, such as in the resulting
error messages for a deeply nested or non-obvious
requirement.
<p>Concepts should be statically verifiable by the compiler.
Do not use any concept whose primary benefits would come from a
semantic (or otherwise unenforced) constraint.
Requirements that are unenforced at compile time should instead
be imposed via other mechanisms such as comments, assertions,
or tests.</p>
<h3 id="Boost">Boost</h3> <h3 id="Boost">Boost</h3>
<p>Use only approved libraries from the Boost library <p>Use only approved libraries from the Boost library
@ -3955,9 +4080,10 @@ guide, the following C++ features may not be used:</p>
<p class="definition"></p> <p class="definition"></p>
<p>There are several ways to create names that are aliases of other entities:</p> <p>There are several ways to create names that are aliases of other entities:</p>
<pre>typedef Foo Bar; <pre>using Bar = Foo;
using Bar = Foo; typedef Foo Bar; // But prefer `using` in C++ code.
using other_namespace::Foo; using ::other_namespace::Foo;
using enum MyEnumType; // Creates aliases for all enumerators in MyEnumType.
</pre> </pre>
<p>In new code, <code>using</code> is preferable to <code>typedef</code>, <p>In new code, <code>using</code> is preferable to <code>typedef</code>,
@ -4245,6 +4371,10 @@ using PropertiesMap = hash_map&lt;UrlTableProperties *, std::string&gt;;
enum class UrlTableError { ... enum class UrlTableError { ...
</pre> </pre>
<h3 id="Concept_Names">Concept Names</h3>
Concept names follow the same rules as <a href="#Type_Names">type names</a>.
<h3 id="Variable_Names">Variable Names</h3> <h3 id="Variable_Names">Variable Names</h3>
<p>The names of variables (including function parameters) and data members are <p>The names of variables (including function parameters) and data members are
@ -4308,9 +4438,10 @@ const int kAndroid8_0_0 = 24; // Android 8.0.0
<p>All such variables with static storage duration (i.e., statics and globals, <p>All such variables with static storage duration (i.e., statics and globals,
see <a href="http://en.cppreference.com/w/cpp/language/storage_duration#Storage_duration"> see <a href="http://en.cppreference.com/w/cpp/language/storage_duration#Storage_duration">
Storage Duration</a> for details) should be named this way. This Storage Duration</a> for details) should be named this way, including those in templates where
convention is optional for variables of other storage classes, e.g., automatic different instantiations of the template may have different values. This convention is optional for
variables; otherwise the usual variable naming rules apply. For example:</p> variables of other storage classes, e.g., automatic variables; otherwise the usual variable naming
rules apply. For example:</p>
<pre>void ComputeFoo(absl::string_view suffix) { <pre>void ComputeFoo(absl::string_view suffix) {
// Either of these is acceptable. // Either of these is acceptable.
@ -4515,7 +4646,7 @@ author line, consider deleting the author line.
New files should usually not contain copyright notice or New files should usually not contain copyright notice or
author line.</p> author line.</p>
<h3 id="Class_Comments">Class Comments</h3> <h3 id="Class_Comments">Struct and Class Comments</h3>
<p>Every non-obvious class or struct declaration should have an <p>Every non-obvious class or struct declaration should have an
accompanying comment that describes what it is for and how it should accompanying comment that describes what it is for and how it should
@ -4532,6 +4663,8 @@ class GargantuanTableIterator {
}; };
</pre> </pre>
<h4 id="Class_Comments_Details">Class Comments</h4>
<p>The class comment should provide the reader with enough information to know <p>The class comment should provide the reader with enough information to know
how and when to use the class, as well as any additional considerations how and when to use the class, as well as any additional considerations
necessary to correctly use the class. Document the synchronization assumptions necessary to correctly use the class. Document the synchronization assumptions
@ -4925,7 +5058,8 @@ if included in the source as straight UTF-8.</p>
<p>When possible, avoid the <code>u8</code> prefix. <p>When possible, avoid the <code>u8</code> prefix.
It has significantly different semantics starting in C++20 It has significantly different semantics starting in C++20
than in C++17, producing arrays of <code>char8_t</code> than in C++17, producing arrays of <code>char8_t</code>
rather than <code>char</code>. rather than <code>char</code>, and will change again in C++23.
</p><p>You shouldn't use <code>char16_t</code> and </p><p>You shouldn't use <code>char16_t</code> and
<code>char32_t</code> character types, since they're for <code>char32_t</code> character types, since they're for
@ -5091,7 +5225,8 @@ double d = 1248e6;
</pre> </pre>
<pre class="goodcode">float f = 1.0f; <pre class="goodcode">float f = 1.0f;
float f2 = 1; // Also OK float f2 = 1.0; // Also OK
float f3 = 1; // Also OK
long double ld = -0.5L; long double ld = -0.5L;
double d = 1248.0e6; double d = 1248.0e6;
</pre> </pre>

View File

@ -597,7 +597,11 @@ to have them in the same package.
Code within a package can access unexported identifiers in the package. If you Code within a package can access unexported identifiers in the package. If you
have a few related types whose *implementation* is tightly coupled, placing them have a few related types whose *implementation* is tightly coupled, placing them
in the same package lets you achieve this coupling without polluting the public in the same package lets you achieve this coupling without polluting the public
API with these details. API with these details. A good test for this coupling is to imagine a
hypothetical user of two packages, where the packages cover closely related
topics: if the user must import both packages in order to use either in any
meaningful way, combining them together is usually the right thing to do. The
standard library generally demonstrates this kind of scoping and layering well.
All of that being said, putting your entire project in a single package would All of that being said, putting your entire project in a single package would
likely make that package too large. When something is conceptually distinct, likely make that package too large. When something is conceptually distinct,
@ -776,7 +780,7 @@ var (
ErrMarsupial = errors.New("marsupials are not supported") ErrMarsupial = errors.New("marsupials are not supported")
) )
func pet(animal Animal) error { func process(animal Animal) error {
switch { switch {
case seen[animal]: case seen[animal]:
return ErrDuplicate return ErrDuplicate
@ -849,6 +853,8 @@ to know if using status codes is the right choice.
[`os.PathError`]: https://pkg.go.dev/os#PathError [`os.PathError`]: https://pkg.go.dev/os#PathError
[`errors.Is`]: https://pkg.go.dev/errors#Is [`errors.Is`]: https://pkg.go.dev/errors#Is
[`errors.As`]: https://pkg.go.dev/errors#As
[`package cmp`]: https://pkg.go.dev/github.com/google/go-cmp/cmp
[status]: https://pkg.go.dev/google.golang.org/grpc/status [status]: https://pkg.go.dev/google.golang.org/grpc/status
[canonical codes]: https://pkg.go.dev/google.golang.org/grpc/codes [canonical codes]: https://pkg.go.dev/google.golang.org/grpc/codes
@ -978,6 +984,10 @@ func (*FortuneTeller) SuggestFortune(context.Context, *pb.SuggestionRequest) (*p
} }
``` ```
See also:
* [Error Documentation Conventions](#documentation-conventions-errors)
<a id="error-percent-w"></a> <a id="error-percent-w"></a>
### Placement of %w in errors ### Placement of %w in errors
@ -1255,7 +1265,7 @@ information to the reader:
// string. // string.
// //
// format is the format, and data is the interpolation data. // format is the format, and data is the interpolation data.
func Sprintf(format string, data ...interface{}) string func Sprintf(format string, data ...any) string
``` ```
However, this snippet demonstrates a code scenario similar to the previous where However, this snippet demonstrates a code scenario similar to the previous where
@ -1272,7 +1282,7 @@ reader:
// the format specification, the function will inline warnings about formatting // the format specification, the function will inline warnings about formatting
// errors into the output string as described by the Format errors section // errors into the output string as described by the Format errors section
// above. // above.
func Sprintf(format string, data ...interface{}) string func Sprintf(format string, data ...any) string
``` ```
Consider your likely audience in choosing what to document and at what depth. Consider your likely audience in choosing what to document and at what depth.
@ -1317,9 +1327,9 @@ func (Worker) Run(ctx context.Context) error
``` ```
Where context behavior is different or non-obvious, it should be expressly Where context behavior is different or non-obvious, it should be expressly
documented: documented if any of the following are true.
* If the function returns an error other than `ctx.Err()` when the context is * The function returns an error other than `ctx.Err()` when the context is
cancelled: cancelled:
```go ```go
@ -1330,8 +1340,7 @@ documented:
func (Worker) Run(ctx context.Context) error func (Worker) Run(ctx context.Context) error
``` ```
* If the function has other mechanisms that may interrupt it or affect * The function has other mechanisms that may interrupt it or affect lifetime:
lifetime:
```go ```go
// Good: // Good:
@ -1347,7 +1356,7 @@ documented:
func (Worker) Stop() func (Worker) Stop()
``` ```
* If the function has special expectations about context lifetime, lineage, or * The function has special expectations about context lifetime, lineage, or
attached values: attached values:
```go ```go
@ -1394,9 +1403,9 @@ Similarly, the extra remark about concurrency can safely be removed here:
func (*Buffer) Grow(n int) func (*Buffer) Grow(n int)
``` ```
Documentation is strongly encouraged if: Documentation is strongly encouraged if any of the following are true.
* it is unclear whether the operation is read-only or a mutating * It is unclear whether the operation is read-only or mutating:
```go ```go
// Good: // Good:
@ -1411,7 +1420,7 @@ Documentation is strongly encouraged if:
Why? A cache hit when looking up the key mutate a LRU cache internally. How Why? A cache hit when looking up the key mutate a LRU cache internally. How
this is implemented may not be obvious to all readers. this is implemented may not be obvious to all readers.
* synchronization is provided by API * Synchronization is provided by the API:
```go ```go
// Good: // Good:
@ -1427,7 +1436,7 @@ Documentation is strongly encouraged if:
**Note:** If the API is a type and the API provides synchronization in **Note:** If the API is a type and the API provides synchronization in
entirety, conventionally only the type definition documents the semantics. entirety, conventionally only the type definition documents the semantics.
* the API consumes user-implemented types of interfaces, and the interface's * The API consumes user-implemented types of interfaces, and the interface's
consumer has particular concurrency requirements: consumer has particular concurrency requirements:
```go ```go
@ -1489,6 +1498,84 @@ If it is potentially unclear how to clean up the resources, explain how:
func (c *Client) Get(url string) (resp *Response, err error) func (c *Client) Get(url string) (resp *Response, err error)
``` ```
See also:
* [GoTip #110: Dont Mix Exit With Defer]
[GoTip #110: Dont Mix Exit With Defer]: https://google.github.io/styleguide/go/index.html#gotip
<a id="documentation-conventions-errors"></a>
#### Errors
Document significant error sentinel values or error types that your functions
return to callers so that callers can anticipate what types of conditions they
can handle in their code.
```go
// Good:
package os
// Read reads up to len(b) bytes from the File and stores them in b. It returns
// the number of bytes read and any error encountered.
//
// At end of file, Read returns 0, io.EOF.
func (*File) Read(b []byte) (n int, err error) {
```
When a function returns a specific error type, correctly note whether the error
is a pointer receiver or not:
```go
// Good:
package os
type PathError struct {
Op string
Path string
Err error
}
// Chdir changes the current working directory to the named directory.
//
// If there is an error, it will be of type *PathError.
func Chdir(dir string) error {
```
Documenting whether the values returned are pointer receivers enables callers to
correctly compare the errors using [`errors.Is`], [`errors.As`], and
[`package cmp`]. This is because a non-pointer value is not equivalent to a
pointer value.
**Note:** In the `Chdir` example, the return type is written as `error` rather
than `*PathError` due to
[how nil interface values work](https://go.dev/doc/faq#nil_error).
Document overall error conventions in the
[package's documentation](decisions#package-comments) when the behavior is
applicable to most errors found in the package:
```go
// Good:
// Package os provides a platform-independent interface to operating system
// functionality.
//
// Often, more information is available within the error. For example, if a
// call that takes a file name fails, such as Open or Stat, the error will
// include the failing file name when printed and will be of type *PathError,
// which may be unpacked for more information.
package os
```
Thoughtful application of these approaches can add
[extra information to errors](#error-extra-info) without much effort and help
callers avoid adding redundant annotations.
See also:
* [Go Tip #106: Error Naming Conventions](https://google.github.io/styleguide/go/index.html#gotip)
* [Go Tip #89: When to Use Canonical Status Codes as Errors](https://google.github.io/styleguide/go/index.html#gotip)
<a id="documentation-preview"></a> <a id="documentation-preview"></a>
### Preview ### Preview
@ -1944,7 +2031,7 @@ func foo(ctx context.Context) {
} }
``` ```
**Note**: [Contexts are never included in option structs](decisions#contexts). **Note:** [Contexts are never included in option structs](decisions#contexts).
This option is often preferred when some of the following apply: This option is often preferred when some of the following apply:
@ -2411,7 +2498,7 @@ func ExerciseGame(t *testing.T, cfg *Config, p chess.Player) error {
if cfg.Simulation == Modem { if cfg.Simulation == Modem {
conn, err := modempool.Allocate() conn, err := modempool.Allocate()
if err != nil { if err != nil {
t.Fatalf("no modem for the opponent could be provisioned: %v", err) t.Fatalf("No modem for the opponent could be provisioned: %v", err)
} }
t.Cleanup(func() { modempool.Return(conn) }) t.Cleanup(func() { modempool.Return(conn) })
} }
@ -2437,7 +2524,7 @@ func TestAcceptance(t *testing.T) {
player := deepblue.New() player := deepblue.New()
err := chesstest.ExerciseGame(t, chesstest.SimpleGame, player) err := chesstest.ExerciseGame(t, chesstest.SimpleGame, player)
if err != nil { if err != nil {
t.Errorf("deepblue player failed acceptance test: %v", err) t.Errorf("Deep Blue player failed acceptance test: %v", err)
} }
} }
``` ```
@ -2578,14 +2665,14 @@ func paint(color string) error {
func badSetup(t *testing.T) { func badSetup(t *testing.T) {
// This should call t.Helper, but doesn't. // This should call t.Helper, but doesn't.
if err := paint("taupe"); err != nil { if err := paint("taupe"); err != nil {
t.Fatalf("could not paint the house under test: %v", err) // line 15 t.Fatalf("Could not paint the house under test: %v", err) // line 15
} }
} }
func mustGoodSetup(t *testing.T) { func mustGoodSetup(t *testing.T) {
t.Helper() t.Helper()
if err := paint("lilac"); err != nil { if err := paint("lilac"); err != nil {
t.Fatalf("could not paint the house under test: %v", err) t.Fatalf("Could not paint the house under test: %v", err)
} }
} }
@ -2605,10 +2692,10 @@ differs:
```text ```text
=== RUN TestBad === RUN TestBad
paint_test.go:15: could not paint the house under test: no "taupe" paint today paint_test.go:15: Could not paint the house under test: no "taupe" paint today
--- FAIL: TestBad (0.00s) --- FAIL: TestBad (0.00s)
=== RUN TestGood === RUN TestGood
paint_test.go:32: could not paint the house under test: no "lilac" paint today paint_test.go:32: Could not paint the house under test: no "lilac" paint today
--- FAIL: TestGood (0.00s) --- FAIL: TestGood (0.00s)
FAIL FAIL
``` ```
@ -2616,7 +2703,7 @@ FAIL
The error with `paint_test.go:15` refers to the line of the setup function that The error with `paint_test.go:15` refers to the line of the setup function that
failed in `badSetup`: failed in `badSetup`:
`t.Fatalf("could not paint the house under test: %v", err)` `t.Fatalf("Could not paint the house under test: %v", err)`
Whereas `paint_test.go:32` refers to the line of the test that failed in Whereas `paint_test.go:32` refers to the line of the test that failed in
`TestGood`: `TestGood`:
@ -2695,33 +2782,41 @@ and those should not depend on the system under test. Therefore, if a test
helper [registers a fatal test failure](#test-helper-error-handling), it can and helper [registers a fatal test failure](#test-helper-error-handling), it can and
should do so from the test's goroutine. should do so from the test's goroutine.
<a id="t-field-names"></a>
### Use field names in struct literals
<a id="t-field-labels"></a> <a id="t-field-labels"></a>
### Use field labels for struct literals In table-driven tests, prefer to specify field names when initializing test case
struct literals. This is helpful when the test cases cover a large amount of
In table-driven tests, prefer to specify the key for each test case specified. vertical space (e.g. more than 20-30 lines), when there are adjacent fields with
This is helpful when the test cases cover a large amount of vertical space (e.g. the same type, and also when you wish to omit fields which have the zero value.
more than 20-30 lines), when there are adjacent fields with the same type, and For example:
also when you wish to omit fields which have the zero value. For example:
```go ```go
// Good: // Good:
tests := []struct { func TestStrJoin(t *testing.T) {
foo *pb.Foo tests := []struct {
bar *pb.Bar slice []string
separator string
skipEmpty bool
want string want string
}{ }{
{ {
foo: pb.Foo_builder{ slice: []string{"a", "b", ""},
Name: "foo", separator: ",",
// ... want: "a,b,",
}.Build(),
bar: pb.Bar_builder{
Name: "bar",
// ...
}.Build(),
want: "result",
}, },
{
slice: []string{"a", "b", ""},
separator: ",",
skipEmpty: true,
want: "a,b",
},
// ...
}
// ...
} }
``` ```
@ -2742,7 +2837,7 @@ func mustLoadDataset(t *testing.T) []byte {
data, err := os.ReadFile("path/to/your/project/testdata/dataset") data, err := os.ReadFile("path/to/your/project/testdata/dataset")
if err != nil { if err != nil {
t.Fatalf("could not load dataset: %v", err) t.Fatalf("Could not load dataset: %v", err)
} }
return data return data
} }
@ -2756,7 +2851,7 @@ func TestParseData(t *testing.T) {
data := mustLoadDataset(t) data := mustLoadDataset(t)
parsed, err := ParseData(data) parsed, err := ParseData(data)
if err != nil { if err != nil {
t.Fatalf("unexpected error parsing data: %v", err) t.Fatalf("Unexpected error parsing data: %v", err)
} }
want := &DataTable{ /* ... */ } want := &DataTable{ /* ... */ }
if got := parsed; !cmp.Equal(got, want) { if got := parsed; !cmp.Equal(got, want) {
@ -2768,7 +2863,7 @@ func TestListContents(t *testing.T) {
data := mustLoadDataset(t) data := mustLoadDataset(t)
contents, err := ListContents(data) contents, err := ListContents(data)
if err != nil { if err != nil {
t.Fatalf("unexpected error listing contents: %v", err) t.Fatalf("Unexpected error listing contents: %v", err)
} }
want := []string{ /* ... */ } want := []string{ /* ... */ }
if got := contents; !cmp.Equal(got, want) { if got := contents; !cmp.Equal(got, want) {
@ -2916,7 +3011,7 @@ func mustLoadDataset(t *testing.T) []byte {
dataset.err = err dataset.err = err
}) })
if err := dataset.err; err != nil { if err := dataset.err; err != nil {
t.Fatalf("could not load dataset: %v", err) t.Fatalf("Could not load dataset: %v", err)
} }
return dataset.data return dataset.data
} }
@ -2972,8 +3067,8 @@ guidance outlines when each method is preferred.
### Prefer "+" for simple cases ### Prefer "+" for simple cases
Prefer using "+" when concatenating few strings. This method is the Prefer using "+" when concatenating few strings. This method is syntactically
syntactically the simplest and requires no import. the simplest and requires no import.
```go ```go
// Good: // Good:
@ -3024,7 +3119,7 @@ for i, d := range digitsOfPi {
str := b.String() str := b.String()
``` ```
**NOTE**: For more discussion, see **Note:** For more discussion, see
[GoTip #29: Building Strings Efficiently](https://google.github.io/styleguide/go/index.html#gotip). [GoTip #29: Building Strings Efficiently](https://google.github.io/styleguide/go/index.html#gotip).
<a id="string-constants"></a> <a id="string-constants"></a>

View File

@ -897,9 +897,14 @@ import (
) )
``` ```
It is acceptable to split the project packages into multiple groups, for example It is acceptable to split the project packages into multiple groups if you want
if you want a separate group for renamed, imported-only-for-side-effects or a separate group, as long as the groups have some meaning. Common reasons to do
another special group of imports. this:
* renamed imports
* packages imported for their side-effects
Example:
```go ```go
// Good: // Good:
@ -1273,14 +1278,19 @@ maintainable.
#### Field names #### Field names
Struct literals should usually specify **field names** for types defined outside Struct literals must specify **field names** for types defined outside the
the current package. current package.
* Include field names for types from other packages. * Include field names for types from other packages.
```go ```go
// Good: // Good:
good := otherpkg.Type{A: 42} // https://pkg.go.dev/encoding/csv#Reader
r := csv.Reader{
Comma: ',',
Comment: '#',
FieldsPerRecord: 4,
}
``` ```
The position of fields in a struct and the full set of fields (both of which The position of fields in a struct and the full set of fields (both of which
@ -1290,19 +1300,9 @@ the current package.
```go ```go
// Bad: // Bad:
// https://pkg.go.dev/encoding/csv#Reader
r := csv.Reader{',', '#', 4, false, false, false, false} r := csv.Reader{',', '#', 4, false, false, false, false}
``` ```
Field names may be omitted within small, simple structs whose composition
and order are documented as being stable.
```go
// Good:
okay := image.Point{42, 54}
also := image.Point{X: 42, Y: 54}
```
* For package-local types, field names are optional. * For package-local types, field names are optional.
```go ```go
@ -1721,33 +1721,6 @@ func (r *SomeType) SomeLongFunctionName(foo1, foo2, foo3 string,
See [best practices](best-practices#funcargs) for a few options for shortening See [best practices](best-practices#funcargs) for a few options for shortening
the call sites of functions that would otherwise have many arguments. the call sites of functions that would otherwise have many arguments.
```go
// Good:
good := foo.Call(long, CallOptions{
Names: list,
Of: of,
The: parameters,
Func: all,
Args: on,
Now: separate,
Visible: lines,
})
```
```go
// Bad:
bad := foo.Call(
long,
list,
of,
parameters,
all,
on,
separate,
lines,
)
```
Lines can often be shortened by factoring out local variables. Lines can often be shortened by factoring out local variables.
```go ```go
@ -1770,9 +1743,9 @@ bad := foo.Call(long, list, of, parameters,
with, arbitrary, line, breaks) with, arbitrary, line, breaks)
``` ```
Do not add comments to specific function parameters. Instead, use an Avoid adding inline comments to specific function arguments where possible.
[option struct](best-practices#option-structure) or add more detail to the Instead, use an [option struct](best-practices#option-structure) or add more
function documentation. detail to the function documentation.
```go ```go
// Good: // Good:
@ -1787,21 +1760,6 @@ bad := server.New(
) )
``` ```
If call-sites are uncomfortably long, consider refactoring:
```go
// Good:
// Sometimes variadic arguments can be factored out
replacements := []string{
"from", "to", // related values can be formatted adjacent to one another
"source", "dest",
"original", "new",
}
// Use the replacement struct as inputs to NewReplacer.
replacer := strings.NewReplacer(replacements...)
```
If the API cannot be changed or if the local call is unusual (whether or not the If the API cannot be changed or if the local call is unusual (whether or not the
call is too long), it is always permissible to add line breaks if it aids in call is too long), it is always permissible to add line breaks if it aids in
understanding the call. understanding the call.
@ -2110,7 +2068,7 @@ exclusively at
func MustParse(version string) *Version { func MustParse(version string) *Version {
v, err := Parse(version) v, err := Parse(version)
if err != nil { if err != nil {
log.Fatalf("MustParse(%q) = _, %v", version, err) panic(fmt.Sprintf("MustParse(%q) = _, %v", version, err))
} }
return v return v
} }
@ -2120,8 +2078,6 @@ func MustParse(version string) *Version {
var DefaultVersion = MustParse("1.2.3") var DefaultVersion = MustParse("1.2.3")
``` ```
**Note:** `log.Fatalf` is not the standard library log. See [#logging].
The same convention may be used in test helpers that only stop the current test The same convention may be used in test helpers that only stop the current test
(using `t.Fatal`). Such helpers are often convenient in creating test values, (using `t.Fatal`). Such helpers are often convenient in creating test values,
for example in struct fields of [table driven tests](#table-driven-tests), as for example in struct fields of [table driven tests](#table-driven-tests), as
@ -2133,7 +2089,7 @@ func mustMarshalAny(t *testing.T, m proto.Message) *anypb.Any {
t.Helper() t.Helper()
any, err := anypb.New(m) any, err := anypb.New(m)
if err != nil { if err != nil {
t.Fatalf("MustMarshalAny(t, m) = %v; want %v", err, nil) t.Fatalf("mustMarshalAny(t, m) = %v; want %v", err, nil)
} }
return any return any
} }
@ -2189,8 +2145,8 @@ func Version(o *servicepb.Object) (*version.Version, error) {
When you spawn goroutines, make it clear when or whether they exit. When you spawn goroutines, make it clear when or whether they exit.
Goroutines can leak by blocking on channel sends or receives. The garbage Goroutines can leak by blocking on channel sends or receives. The garbage
collector will not terminate a goroutine even if the channels it is blocked on collector will not terminate a goroutine blocked on a channel even if no other
are unreachable. goroutine has a reference to the channel.
Even when goroutines do not leak, leaving them in-flight when they are no longer Even when goroutines do not leak, leaving them in-flight when they are no longer
needed can cause other subtle and hard-to-diagnose problems. Sending on a needed can cause other subtle and hard-to-diagnose problems. Sending on a
@ -2764,11 +2720,11 @@ See also:
### Logging ### Logging
Go programs in the Google codebase use a variant of the Go programs in the Google codebase use a variant of the standard [`log`]
[standard `log` package]. It has a similar but more powerful interface and package. It has a similar but more powerful interface and interoperates well
interoperates well with internal Google systems. An open source version of this with internal Google systems. An open source version of this library is
library is available as [package `glog`], and open source Google projects may available as [package `glog`], and open source Google projects may use that, but
use that, but this guide refers to it as `log` throughout. this guide refers to it as `log` throughout.
**Note:** For abnormal program exits, this library uses `log.Fatal` to abort **Note:** For abnormal program exits, this library uses `log.Fatal` to abort
with a stacktrace, and `log.Exit` to stop without one. There is no `log.Panic` with a stacktrace, and `log.Exit` to stop without one. There is no `log.Panic`
@ -2785,7 +2741,8 @@ See also:
* When and how to use the log package to * When and how to use the log package to
[stop the program](best-practices#checks-and-panics) [stop the program](best-practices#checks-and-panics)
[standard `log` package]: https://pkg.go.dev/log [`log`]: https://pkg.go.dev/log
[`log/slog`]: https://pkg.go.dev/log/slog
[package `glog`]: https://pkg.go.dev/github.com/golang/glog [package `glog`]: https://pkg.go.dev/github.com/golang/glog
[`log.Exit`]: https://pkg.go.dev/github.com/golang/glog#Exit [`log.Exit`]: https://pkg.go.dev/github.com/golang/glog#Exit
[`log.Fatal`]: https://pkg.go.dev/github.com/golang/glog#Fatal [`log.Fatal`]: https://pkg.go.dev/github.com/golang/glog#Fatal
@ -2978,15 +2935,15 @@ right:
// Bad: // Bad:
package assert package assert
func IsNotNil(t *testing.T, name string, val interface{}) { func IsNotNil(t *testing.T, name string, val any) {
if val == nil { if val == nil {
t.Fatalf("data %s = nil, want not nil", name) t.Fatalf("Data %s = nil, want not nil", name)
} }
} }
func StringEq(t *testing.T, name, got, want string) { func StringEq(t *testing.T, name, got, want string) {
if got != want { if got != want {
t.Fatalf("data %s = %q, want %q", name, got, want) t.Fatalf("Data %s = %q, want %q", name, got, want)
} }
} }
``` ```
@ -3013,7 +2970,7 @@ want := BlogPost{
} }
if !cmp.Equal(got, want) { if !cmp.Equal(got, want) {
t.Errorf("blog post = %v, want = %v", got, want) t.Errorf("Blog post = %v, want = %v", got, want)
} }
``` ```
@ -3029,7 +2986,7 @@ func TestBlogPost_VeritableRant(t *testing.T) {
post := BlogPost{Body: "I am Gunnery Sergeant Hartman, your senior drill instructor."} post := BlogPost{Body: "I am Gunnery Sergeant Hartman, your senior drill instructor."}
if got, want := postLength(post), 60; got != want { if got, want := postLength(post), 60; got != want {
t.Errorf("length of post = %v, want %v", got, want) t.Errorf("Length of post = %v, want %v", got, want)
} }
} }
``` ```
@ -3361,7 +3318,8 @@ than relying on parsing the error message.
Within unit tests, it is common to only care whether an error occurred or not. Within unit tests, it is common to only care whether an error occurred or not.
If so, then it is sufficient to only test whether the error was non-nil when you If so, then it is sufficient to only test whether the error was non-nil when you
expected an error. If you would like to test that the error semantically matches expected an error. If you would like to test that the error semantically matches
some other error, then consider using `cmp` with [`cmpopts.EquateErrors`]. some other error, then consider using [`errors.Is`] or `cmp` with
[`cmpopts.EquateErrors`].
> **Note:** If a test uses [`cmpopts.EquateErrors`] but all of its `wantErr` > **Note:** If a test uses [`cmpopts.EquateErrors`] but all of its `wantErr`
> values are either `nil` or `cmpopts.AnyError`, then using `cmp` is > values are either `nil` or `cmpopts.AnyError`, then using `cmp` is
@ -3370,9 +3328,10 @@ some other error, then consider using `cmp` with [`cmpopts.EquateErrors`].
> >
> ```go > ```go
> // Good: > // Good:
> gotErr := f(test.input) != nil > err := f(test.input)
> gotErr := err != nil
> if gotErr != test.wantErr { > if gotErr != test.wantErr {
> t.Errorf("f(%q) returned err = %v, want error presence = %v", test.input, gotErr, test.wantErr) > t.Errorf("f(%q) = %v, want error presence = %v", test.input, err, test.wantErr)
> } > }
> ``` > ```
@ -3381,6 +3340,7 @@ See also
[tott-350]: https://testing.googleblog.com/2015/01/testing-on-toilet-change-detector-tests.html [tott-350]: https://testing.googleblog.com/2015/01/testing-on-toilet-change-detector-tests.html
[`cmpopts.EquateErrors`]: https://pkg.go.dev/github.com/google/go-cmp/cmp/cmpopts#EquateErrors [`cmpopts.EquateErrors`]: https://pkg.go.dev/github.com/google/go-cmp/cmp/cmpopts#EquateErrors
[`errors.Is`]: https://pkg.go.dev/errors#Is
<a id="test-structure"></a> <a id="test-structure"></a>
@ -3471,6 +3431,9 @@ t.Run("check that there is no mention of scratched records or hovercrafts", ...)
t.Run("AM/PM confusion", ...) t.Run("AM/PM confusion", ...)
``` ```
See also
[Go Tip #117: Subtest Names](https://google.github.io/styleguide/go/index.html#gotip).
[Go test runner]: https://golang.org/cmd/go/#hdr-Testing_flags [Go test runner]: https://golang.org/cmd/go/#hdr-Testing_flags
[identify the inputs]: #identify-the-input [identify the inputs]: #identify-the-input
[special meaning for test filters]: https://blog.golang.org/subtests#:~:text=Perhaps%20a%20bit,match%20any%20tests [special meaning for test filters]: https://blog.golang.org/subtests#:~:text=Perhaps%20a%20bit,match%20any%20tests
@ -3491,18 +3454,17 @@ similar testing logic.
[tests of `fmt.Sprintf`]: https://cs.opensource.google/go/go/+/master:src/fmt/fmt_test.go [tests of `fmt.Sprintf`]: https://cs.opensource.google/go/go/+/master:src/fmt/fmt_test.go
[tests for `net.Dial`]: https://cs.opensource.google/go/go/+/master:src/net/dial_test.go;l=318;drc=5b606a9d2b7649532fe25794fa6b99bd24e7697c [tests for `net.Dial`]: https://cs.opensource.google/go/go/+/master:src/net/dial_test.go;l=318;drc=5b606a9d2b7649532fe25794fa6b99bd24e7697c
Here is the minimal structure of a table-driven test, copied from the standard Here is the minimal structure of a table-driven test. If needed, you may use
`strings` library. If needed, you may use different names, move the test slice different names or add extra facilities such as subtests or setup and cleanup
into the test function, or add extra facilities such as subtests or setup and functions. Always keep [useful test failures](#useful-test-failures) in mind.
cleanup functions. Always keep [useful test failures](#useful-test-failures) in
mind.
```go ```go
// Good: // Good:
var compareTests = []struct { func TestCompare(t *testing.T) {
compareTests := []struct {
a, b string a, b string
i int want int
}{ }{
{"", "", 0}, {"", "", 0},
{"a", "", 1}, {"a", "", 1},
{"", "a", -1}, {"", "a", -1},
@ -3517,13 +3479,12 @@ var compareTests = []struct {
{"abcdefgh", "abcdefgh", 0}, {"abcdefgh", "abcdefgh", 0},
{"abcdefghi", "abcdefghi", 0}, {"abcdefghi", "abcdefghi", 0},
{"abcdefghi", "abcdefghj", -1}, {"abcdefghi", "abcdefghj", -1},
} }
func TestCompare(t *testing.T) { for _, test := range compareTests {
for _, tt := range compareTests { got := Compare(test.a, test.b)
cmp := Compare(tt.a, tt.b) if got != test.want {
if cmp != tt.i { t.Errorf("Compare(%q, %q) = %v, want %v", test.a, test.b, got, test.want)
t.Errorf(`Compare(%q, %q) = %v`, tt.a, tt.b, cmp)
} }
} }
} }
@ -3639,7 +3600,7 @@ func TestDecode(t *testing.T) {
case prod: case prod:
codex = setupCodex(t) codex = setupCodex(t)
default: default:
t.Fatalf("unknown codex type: %v", codex) t.Fatalf("Unknown codex type: %v", codex)
} }
output, err := Decode(test.input, codex) output, err := Decode(test.input, codex)
if got, want := output, test.output; got != want { if got, want := output, test.output; got != want {
@ -3673,7 +3634,7 @@ tests := []struct {
} }
for i, d := range tests { for i, d := range tests {
if strings.ToUpper(d.input) != d.want { if strings.ToUpper(d.input) != d.want {
t.Errorf("failed on case #%d", i) t.Errorf("Failed on case #%d", i)
} }
} }
``` ```

View File

@ -419,8 +419,8 @@ initial capitalization.
### Line length ### Line length
There is no fixed line length for Go source code. If a line feels too long, it There is no fixed line length for Go source code. If a line feels too long,
should be refactored instead of broken. If it is already as short as it is prefer refactoring instead of splitting it. If it is already as short as it is
practical for it to be, the line should be allowed to remain long. practical for it to be, the line should be allowed to remain long.
Do not split a line: Do not split a line:

View File

@ -2,13 +2,16 @@ table {
border-collapse: collapse; border-collapse: collapse;
} }
td, th { td,
th {
border: 1px solid #ccc; border: 1px solid #ccc;
padding: 2px 12px; padding: 2px 12px;
font-size: 10pt; font-size: 10pt;
} }
code, samp, var { code,
samp,
var {
color: #060; color: #060;
} }
@ -17,16 +20,9 @@ pre {
display: block; display: block;
color: #060; color: #060;
background-color: #e8fff6; background-color: #e8fff6;
border-color: #f0fff0; border: 1px solid #f0fff0;
border-style: solid;
border-top-width: 1px;
border-bottom-width: 1px;
border-right-width: 1px;
border-left-width: 5px; border-left-width: 5px;
padding-left: 12px; padding: 4px 12px;
padding-right: 12px;
padding-top: 4px;
padding-bottom: 4px;
} }
pre.badcode { pre.badcode {
@ -42,10 +38,8 @@ hr {
} }
html { html {
margin-top:2em; margin: 2em 10% 0;
margin-left:10%; padding: 0;
margin-right:10%;
padding:0;
} }
.bp-reset-element, .bp-reset-element,
@ -104,32 +98,32 @@ tbody,
tfoot, tfoot,
thead, thead,
tr { tr {
margin:0; margin: 0;
padding:0; padding: 0;
border:0; border: 0;
font-weight:inherit; font-weight: inherit;
font-style:inherit; font-style: inherit;
font-size:100%; font-size: 100%;
font-family:inherit; font-family: inherit;
vertical-align:baseline; vertical-align: baseline;
} }
body { body {
font-family:'Arial', sans-serif; font-family: 'Arial', sans-serif;
font-size:81.25%; font-size: 81.25%;
color:#222; color: #222;
background-color:#fff; background-color: #fff;
line-height:1.67; line-height: 1.67;
overflow: auto; overflow: auto;
} }
.change { .change {
text-align: right; text-align: right;
margin-bottom:1em; margin-bottom: 1em;
} }
em { em {
font-style: italic font-style: italic;
} }
h1, h1,
@ -138,12 +132,12 @@ h3,
h4, h4,
h5, h5,
h6 { h6 {
font-weight:bold; font-weight: bold;
} }
h1 { h1 {
margin-bottom:.50em; margin-bottom: 0.5em;
text-align: center text-align: center;
} }
h2, h2,
@ -151,22 +145,36 @@ h3,
h4, h4,
h5, h5,
h6 { h6 {
margin-top:1.5em; margin-top: 1.5em;
margin-bottom:.75em; margin-bottom: 0.75em;
} }
h1 {font-size:200%;} h1 {
h2 {font-size:167%;} font-size: 200%;
h3 {font-size:133%;} }
h4 {font-size:120%;}
h5 {font-size:110%;} h2 {
font-size: 167%;
}
h3 {
font-size: 133%;
}
h4 {
font-size: 120%;
}
h5 {
font-size: 110%;
}
p { p {
margin:0 0 1.5em; margin: 0 0 1.5em;
} }
a[href=''] { a[href=''] {
cursor:default; cursor: default;
} }
h1 img, h1 img,
@ -175,238 +183,238 @@ h3 img,
h4 img, h4 img,
h5 img, h5 img,
h6 img { h6 img {
margin:0; margin: 0;
} }
a img { a img {
border:none; border: none;
} }
pre { pre {
margin:1.5em 0; margin: 1.5em 0;
white-space:pre; white-space: pre;
} }
pre, pre,
code, code,
kbd, kbd,
tt { tt {
font:1em 'Droid Sans Mono', monospace; font: 1em 'Droid Sans Mono', monospace;
line-height:1.5; line-height: 1.5;
} }
dl { dl {
margin:0 0 1.5em 0; margin: 0 0 1.5em;
} }
dl dt { dl dt {
font-weight:bold; font-weight: bold;
} }
dd { dd {
margin-left:1.5em; margin-left: 1.5em;
} }
dd.toc3 { dd.toc3 {
margin-left:3em; margin-left: 3em;
} }
hr { hr {
height:0; height: 0;
border:0; border: 0;
border-top:1px solid #ccc; border-top: 1px solid #ccc;
background-color:#ccc; background-color: #ccc;
} }
table { table {
border:1px solid #bbb; border: 1px solid #bbb;
border-spacing:0; border-spacing: 0;
border-collapse:collapse; border-collapse: collapse;
margin:0 0 1.5em; margin: 0 0 1.5em;
vertical-align:middle; vertical-align: middle;
width:100%; width: 100%;
} }
table.unlined, table.unlined,
table.unlined th, table.unlined th,
table.unlined tr, table.unlined tr,
table.unlined td { table.unlined td {
border:0; border: 0;
} }
th, th,
td, td,
caption { caption {
float:none !important; float: none !important;
text-align:left; text-align: left;
font-weight:normal; font-weight: normal;
vertical-align:middle; vertical-align: middle;
padding:4px; padding: 4px;
} }
caption { caption {
padding:0; padding: 0;
} }
td { td {
border:1px solid #bbb; border: 1px solid #bbb;
vertical-align:top; vertical-align: top;
} }
th { th {
border:0; border: 0;
border-bottom:1px solid black; border-bottom: 1px solid black;
font-weight:bold; font-weight: bold;
background:rgb(229, 236, 249); background: rgb(229, 236, 249);
} }
table th code { table th code {
background-color:inherit; background-color: inherit;
color:inherit; color: inherit;
} }
table tfoot th { table tfoot th {
border:1px solid #bbb; border: 1px solid #bbb;
} }
tfoot { tfoot {
font-style:italic; font-style: italic;
} }
caption { caption {
background:#eee; background: #eee;
} }
table[border='0'] { table[border='0'] {
border:none; border: none;
} }
table[border='0']>tbody>tr>td, table[border='0'] > tbody > tr > td,
table[border='0']>tr>td { table[border='0'] > tr > td {
border:none; border: none;
} }
tr.alt td, tr.alt td,
td.alt { td.alt {
background-color:#efefef; background-color: #efefef;
} }
table.striped tr:nth-child(even) td, table.striped tr:nth-child(even) td,
table tr.even td { table tr.even td {
background:#efefef; background: #efefef;
} }
table.columns { table.columns {
border:none; border: none;
} }
table.columns>tbody>tr>td, table.columns > tbody > tr > td,
table.columns>tr>td { table.columns > tr > td {
border:none; border: none;
padding:0 3em 0 0; padding: 0 3em 0 0;
} }
table.columns>tbody>tr>td:last-child, table.columns > tbody > tr > td:last-child,
table.columns>tr>td:last-child { table.columns > tr > td:last-child {
border:none; border: none;
padding:0; padding: 0;
} }
ul, ul,
ol { ol {
margin:0 1.5em 1.5em 0; margin: 0 1.5em 1.5em 0;
padding-left:2em; padding-left: 2em;
} }
li ul, li ul,
li ol { li ol {
margin:0; margin: 0;
} }
ul { ul {
list-style-type:disc; list-style-type: disc;
} }
ol { ol {
list-style-type:decimal; list-style-type: decimal;
} }
ul { ul {
list-style-type:disc; list-style-type: disc;
} }
ul ul { ul ul {
list-style-type:circle; list-style-type: circle;
} }
ul ul ul { ul ul ul {
list-style-type:square; list-style-type: square;
} }
ul.disc { ul.disc {
list-style-type:disc; list-style-type: disc;
} }
ul.circle { ul.circle {
list-style-type:circle; list-style-type: circle;
} }
ul.square { ul.square {
list-style-type:square; list-style-type: square;
} }
ol { ol {
list-style-type:decimal; list-style-type: decimal;
} }
ol ol { ol ol {
list-style-type:lower-alpha; list-style-type: lower-alpha;
} }
ol ol ol { ol ol ol {
list-style-type:lower-roman; list-style-type: lower-roman;
} }
ol ul { ol ul {
list-style-type:circle; list-style-type: circle;
} }
ol.decimal { ol.decimal {
list-style-type:decimal; list-style-type: decimal;
} }
ol.upper-alpha { ol.upper-alpha {
list-style-type:upper-alpha; list-style-type: upper-alpha;
} }
ol.lower-alpha { ol.lower-alpha {
list-style-type:lower-alpha; list-style-type: lower-alpha;
} }
ol.upper-roman { ol.upper-roman {
list-style-type:upper-roman; list-style-type: upper-roman;
} }
ol.lower-roman { ol.lower-roman {
list-style-type:lower-roman; list-style-type: lower-roman;
} }
ol.nolist, ol.nolist,
ul.nolist { ul.nolist {
padding-left:0; padding-left: 0;
list-style-image:none; list-style-image: none;
list-style-type:none; list-style-type: none;
margin-left:0; margin-left: 0;
} }
.center { .center {
text-align:center; text-align: center;
} }
code, code,
kbd, kbd,
pre { pre {
color:#009900; color: #090;
} }
kbd { kbd {
@ -414,107 +422,108 @@ kbd {
} }
table.striped code { table.striped code {
background-color:inherit; background-color: inherit;
} }
pre { pre {
padding:6px 10px; padding: 6px 10px;
background-color:#FAFAFA; background-color: #fafafa;
border:1px solid #bbb; border: 1px solid #bbb;
overflow:auto; overflow: auto;
} }
pre.prettyprint { pre.prettyprint {
padding:6px 10px !important; padding: 6px 10px !important;
border:1px solid #bbb !important; border: 1px solid #bbb !important;
} }
code.bad, code.badcode { code.bad,
code.badcode {
color: magenta; color: magenta;
} }
pre.bad, pre.badcode {
background-color:#ffe6d8; pre.bad,
border-top:1px inset #a03; pre.badcode {
border-left:1px inset #a03; background-color: #ffe6d8;
border-top: 1px inset #a03;
border-left: 1px inset #a03;
} }
.tip { .tip {
background-color:#fffbd9; background-color: #fffbd9;
padding:6px 8px 6px 10px; padding: 6px 8px 6px 10px;
border-left:6px solid #ffef70; border-left: 6px solid #ffef70;
} }
.note { .note {
background-color:#e5ecf9; background-color: #e5ecf9;
padding:6px 8px 6px 10px; padding: 6px 8px 6px 10px;
border-left:6px solid #36c; border-left: 6px solid #36c;
} }
@media print { @media print {
.str { .str {
color:#060; color: #060;
} }
.kwd { .kwd {
color:#006; color: #006;
font-weight:bold; font-weight: bold;
} }
.com { .com {
color:#600; color: #600;
font-style:italic; font-style: italic;
} }
.typ { .typ {
color:#404; color: #404;
font-weight:bold; font-weight: bold;
} }
.lit { .lit {
color:#044; color: #044;
} }
.pun, .pun,
.opn, .opn,
.clo { .clo {
color:#440; color: #440;
} }
.pln { .pln {
color:#000; color: #000;
} }
.tag { .tag {
color:#006; color: #006;
font-weight:bold; font-weight: bold;
} }
.atn { .atn {
color:#404; color: #404;
} }
.atv { .atv {
color:#060; color: #060;
} }
h1 { h1 {
font-style:italic; font-style: italic;
} }
} }
ol.linenums { ol.linenums {
margin-top:0; margin-top: 0;
margin-bottom:0; margin-bottom: 0;
} }
code { code {
background-color:#FAFAFA; background-color: #fafafa;
padding: 0.25em 0.5em; padding: 0.25em 0.5em;
white-space: nowrap white-space: nowrap;
} }
/* TOC CSS */ /* TOC CSS */
table.columns { table.columns {
@ -552,15 +561,16 @@ li.toc_entry {
* at href boundaries * at href boundaries
*/ */
li.toc_entry::after { li.toc_entry::after {
content: " "; content: ' ';
} }
li.toc_entry a { li.toc_entry a {
white-space: nowrap; white-space: nowrap;
} }
/* Horizontal TOC */ /* Horizontal TOC */
.toc td, .toc th { .toc td,
.toc th {
border-width: 1px 5px; border-width: 1px 5px;
overflow: hidden; overflow: hidden;
} }
@ -568,7 +578,7 @@ li.toc_entry a {
/* Vertical TOC */ /* Vertical TOC */
.toc td.two_columns { .toc td.two_columns {
border-width: 0px; border-width: 0;
} }
/* Numbered sections */ /* Numbered sections */

View File

@ -47,6 +47,7 @@ See README.md for details.
+ [3.8.2 Modules](#s3.8.2-comments-in-modules) + [3.8.2 Modules](#s3.8.2-comments-in-modules)
+ [3.8.2.1 Test modules](#s3.8.2.1-test-modules) + [3.8.2.1 Test modules](#s3.8.2.1-test-modules)
+ [3.8.3 Functions and Methods](#s3.8.3-functions-and-methods) + [3.8.3 Functions and Methods](#s3.8.3-functions-and-methods)
+ [3.8.3.1 Overridden Methods](#s3.8.3.1-overridden-methods)
+ [3.8.4 Classes](#s3.8.4-comments-in-classes) + [3.8.4 Classes](#s3.8.4-comments-in-classes)
+ [3.8.5 Block and Inline Comments](#s3.8.5-block-and-inline-comments) + [3.8.5 Block and Inline Comments](#s3.8.5-block-and-inline-comments)
+ [3.8.6 Punctuation, Spelling, and Grammar](#s3.8.6-punctuation-spelling-and-grammar) + [3.8.6 Punctuation, Spelling, and Grammar](#s3.8.6-punctuation-spelling-and-grammar)
@ -213,8 +214,8 @@ that the arguments are actually unused.
<a id="imports"></a> <a id="imports"></a>
### 2.2 Imports ### 2.2 Imports
Use `import` statements for packages and modules only, not for individual Use `import` statements for packages and modules only, not for individual types,
classes or functions. classes, or functions.
<a id="s2.2.1-definition"></a> <a id="s2.2.1-definition"></a>
<a id="221-definition"></a> <a id="221-definition"></a>
@ -404,11 +405,15 @@ Exceptions must follow certain conditions:
- Make use of built-in exception classes when it makes sense. For example, - Make use of built-in exception classes when it makes sense. For example,
raise a `ValueError` to indicate a programming mistake like a violated raise a `ValueError` to indicate a programming mistake like a violated
precondition (such as if you were passed a negative number but required a precondition, such as may happen when validating function arguments.
positive one). Do not use `assert` statements for validating argument values
of a public API. `assert` is used to ensure internal correctness, not to - Do not use `assert` statements in place of conditionals or validating
enforce correct usage nor to indicate that some unexpected event occurred. preconditions. They must not be critical to the application logic. A litmus
If an exception is desired in the latter cases, use a raise statement. For test would be that the `assert` could be removed without breaking the code.
`assert` conditionals are
[not guaranteed](https://docs.python.org/3/reference/simple_stmts.html#the-assert-statement)
to be evaluated. For [pytest](https://pytest.org) based tests, `assert` is
okay and expected to verify expectations. For
example: example:
@ -435,6 +440,7 @@ Exceptions must follow certain conditions:
if port is None: if port is None:
raise ConnectionError( raise ConnectionError(
f'Could not connect to service on port {minimum} or higher.') f'Could not connect to service on port {minimum} or higher.')
# The code does not depend on the result of this assert.
assert port >= minimum, ( assert port >= minimum, (
f'Unexpected port {port} when minimum was {minimum}.') f'Unexpected port {port} when minimum was {minimum}.')
return port return port
@ -452,8 +458,10 @@ Exceptions must follow certain conditions:
The new minimum port. The new minimum port.
""" """
assert minimum >= 1024, 'Minimum port must be at least 1024.' assert minimum >= 1024, 'Minimum port must be at least 1024.'
# The following code depends on the previous assert.
port = self._find_next_open_port(minimum) port = self._find_next_open_port(minimum)
assert port is not None assert port is not None
# The type checking of the return statement relies on the assert.
return port return port
``` ```
@ -642,20 +650,18 @@ Complicated comprehensions or generator expressions can be hard to read.
<a id="comprehensions-decision"></a> <a id="comprehensions-decision"></a>
#### 2.7.4 Decision #### 2.7.4 Decision
Okay to use for simple cases. Each portion must fit on one line: mapping Comprehensions are allowed, however multiple `for` clauses or filter expressions
expression, `for` clause, filter expression. Multiple `for` clauses or filter are not permitted. Optimize for readability, not conciseness.
expressions are not permitted. Use loops instead when things get more
complicated.
```python ```python
Yes: Yes:
result = [mapping_expr for value in iterable if filter_expr] result = [mapping_expr for value in iterable if filter_expr]
result = [{'key': value} for value in iterable result = [
if a_long_filter_expression(value)] is_valid(metric={'key': value})
for value in interesting_iterable
result = [complicated_transform(x) if a_longer_filter_expression(value)
for x in iterable if predicate(x)] ]
descriptive_name = [ descriptive_name = [
transform({'key': key, 'value': value}, color='black') transform({'key': key, 'value': value}, color='black')
@ -669,32 +675,29 @@ Yes:
if x * y > 10: if x * y > 10:
result.append((x, y)) result.append((x, y))
return {x: complicated_transform(x) return {
x: complicated_transform(x)
for x in long_generator_function(parameter) for x in long_generator_function(parameter)
if x is not None} if x is not None
}
squares_generator = (x**2 for x in range(10)) return (x**2 for x in range(10))
unique_names = {user.name for user in users if user is not None} unique_names = {user.name for user in users if user is not None}
eat(jelly_bean for jelly_bean in jelly_beans
if jelly_bean.color == 'black')
``` ```
```python ```python
No: No:
result = [complicated_transform(
x, some_argument=x+1)
for x in iterable if predicate(x)]
result = [(x, y) for x in range(10) for y in range(5) if x * y > 10] result = [(x, y) for x in range(10) for y in range(5) if x * y > 10]
return ((x, y, z) return (
(x, y, z)
for x in range(5) for x in range(5)
for y in range(5) for y in range(5)
if x != y if x != y
for z in range(5) for z in range(5)
if y != z) if y != z
)
``` ```
<a id="s2.8-default-iterators-and-operators"></a> <a id="s2.8-default-iterators-and-operators"></a>
@ -848,8 +851,8 @@ function may only contain an expression.
<a id="lambdas-decision"></a> <a id="lambdas-decision"></a>
#### 2.10.4 Decision #### 2.10.4 Decision
Okay to use them for one-liners. If the code inside the lambda function is Lambdas are allowed. If the code inside the lambda function spans multiple lines
longer than 60-80 chars, it's probably better to define it as a regular or is longer than 60-80 chars, it might be better to define it as a regular
[nested function](#lexical-scoping). [nested function](#lexical-scoping).
For common operations like multiplication, use the functions from the `operator` For common operations like multiplication, use the functions from the `operator`
@ -992,7 +995,7 @@ _FOO = flags.DEFINE_string(...)
No: def foo(a, b=[]): No: def foo(a, b=[]):
... ...
No: def foo(a, b=time.time()): # The time the module was loaded??? No: def foo(a, b=time.time()): # Is `b` supposed to represent when this module was loaded?
... ...
No: def foo(a, b=_FOO.value): # sys.argv has not yet been parsed... No: def foo(a, b=_FOO.value): # sys.argv has not yet been parsed...
... ...
@ -1071,7 +1074,7 @@ implement computations a subclass may ever want to override and extend.
<a id="truefalse-evaluations"></a> <a id="truefalse-evaluations"></a>
### 2.14 True/False Evaluations ### 2.14 True/False Evaluations
Use the "implicit" false if at all possible. Use the "implicit" false if at all possible (with a few caveats).
<a id="s2.14.1-definition"></a> <a id="s2.14.1-definition"></a>
<a id="2141-definition"></a> <a id="2141-definition"></a>
@ -1798,6 +1801,150 @@ Trailing commas in sequences of items are recommended only when the closing
container token `]`, `)`, or `}` does not appear on the same line as the final container token `]`, `)`, or `}` does not appear on the same line as the final
element, as well as for tuples with a single element. The presence of a trailing element, as well as for tuples with a single element. The presence of a trailing
comma is also used as a hint to our Python code auto-formatter comma is also used as a hint to our Python code auto-formatter
[Black](https://github.com/psf/black) or [Pyink](https://github.com/google/pyink)
to direct it to auto-format the container of items to one item per line when the
`,` after the final element is present.
```python
Yes: golomb3 = [0, 1, 3]
golomb4 = [
0,
1,
4,
6,
]
```
```python
No: golomb4 = [
0,
1,
4,
6,]
```
<a id="s3.5-blank-lines"></a>
<a id="35-blank-lines"></a>
<a id="blank-lines"></a>
### 3.5 Blank Lines
Two blank lines between top-level definitions, be they function or class
definitions. One blank line between method definitions and between the docstring
of a `class` and the first method. No blank line following a `def` line. Use
single blank lines as you judge appropriate within functions or methods.
Blank lines need not be anchored to the definition. For example, related
comments immediately preceding function, class, and method definitions can make
sense. Consider if your comment might be more useful as part of the docstring.
<a id="s3.6-whitespace"></a>
<a id="36-whitespace"></a>
<a id="whitespace"></a>
### 3.6 Whitespace
Follow standard typographic rules for the use of spaces around punctuation.
No whitespace inside parentheses, brackets or braces.
```python
Yes: spam(ham[1], {'eggs': 2}, [])
```
```python
No: spam( ham[ 1 ], { 'eggs': 2 }, [ ] )
```
No whitespace before a comma, semicolon, or colon. Do use whitespace after a
comma, semicolon, or colon, except at the end of the line.
```python
Yes: if x == 4:
print(x, y)
x, y = y, x
```
```python
No: if x == 4 :
print(x , y)
x , y = y , x
```
No whitespace before the open paren/bracket that starts an argument list,
indexing or slicing.
```python
Yes: spam(1)
```
```python
No: spam (1)
```
```python
Yes: dict['key'] = list[index]
```
```python
No: dict ['key'] = list [index]
```
No trailing whitespace.
Surround binary operators with a single space on either side for assignment
(`=`), comparisons (`==, <, >, !=, <>, <=, >=, in, not in, is, is not`), and
Booleans (`and, or, not`). Use your better judgment for the insertion of spaces
around arithmetic operators (`+`, `-`, `*`, `/`, `//`, `%`, `**`, `@`).
```python
Yes: x == 1
```
```python
No: x<1
```
Never use spaces around `=` when passing keyword arguments or defining a default
parameter value, with one exception:
[when a type annotation is present](#typing-default-values), *do* use spaces
around the `=` for the default parameter value.
```python
Yes: def complex(real, imag=0.0): return Magic(r=real, i=imag)
Yes: def complex(real, imag: float = 0.0): return Magic(r=real, i=imag)
```
```python
No: def complex(real, imag = 0.0): return Magic(r = real, i = imag)
No: def complex(real, imag: float=0.0): return Magic(r = real, i = imag)
```
Don't use spaces to vertically align tokens on consecutive lines, since it
becomes a maintenance burden (applies to `:`, `#`, `=`, etc.):
```python
Yes:
foo = 1000 # comment
long_name = 2 # comment that should not be aligned
dictionary = {
'foo': 1,
'long_name': 2,
}
```
```python
No:
foo = 1000 # comment
long_name = 2 # comment that should not be aligned
dictionary = {
'foo' : 1,
'long_name': 2,
}
```
<a id="Python_Interpreter"></a> <a id="Python_Interpreter"></a>
<a id="s3.7-shebang-line"></a> <a id="s3.7-shebang-line"></a>
@ -1929,15 +2076,6 @@ should use the same style as the docstring for an attribute or a
<a href="#doc-function-args">function argument</a> (`"""The Bigtable path."""`, <a href="#doc-function-args">function argument</a> (`"""The Bigtable path."""`,
rather than `"""Returns the Bigtable path."""`). rather than `"""Returns the Bigtable path."""`).
A method that overrides a method from a base class may have a simple docstring
sending the reader to its overridden method's docstring, such as `"""See base
class."""`. The rationale is that there is no need to repeat in many places
documentation that is already present in the base method's docstring. However,
if the overriding method's behavior is substantially different from the
overridden method, or details need to be provided (e.g., documenting additional
side effects), a docstring with at least those differences is required on the
overriding method.
Certain aspects of a function should be documented in special sections, listed Certain aspects of a function should be documented in special sections, listed
below. Each section begins with a heading line, which ends with a colon. All below. Each section begins with a heading line, which ends with a colon. All
sections other than the heading should maintain a hanging indent of two or four sections other than the heading should maintain a hanging indent of two or four
@ -1961,16 +2099,18 @@ aptly described using a one-line docstring.
: Describe the semantics of the return value, including any type information : Describe the semantics of the return value, including any type information
that the type annotation does not provide. If the function only returns that the type annotation does not provide. If the function only returns
None, this section is not required. It may also be omitted if the docstring None, this section is not required. It may also be omitted if the docstring
starts with Returns or Yields (e.g. `"""Returns row from Bigtable as a tuple starts with "Return", "Returns", "Yield", or "Yields" (e.g. `"""Returns row
of strings."""`) and the opening sentence is sufficient to describe the from Bigtable as a tuple of strings."""`) *and* the opening sentence is
return value. Do not imitate 'NumPy style' sufficient to describe the return value. Do not imitate older 'NumPy style'
([example](http://numpy.org/doc/stable/reference/generated/numpy.linalg.qr.html)), ([example](https://numpy.org/doc/1.24/reference/generated/numpy.linalg.qr.html)),
which frequently documents a tuple return value as if it were multiple which frequently documented a tuple return value as if it were multiple
return values with individual names (never mentioning the tuple). Instead, return values with individual names (never mentioning the tuple). Instead,
describe such a return value as: "Returns: A tuple (mat_a, mat_b), where describe such a return value as: "Returns: A tuple (mat_a, mat_b), where
mat_a is ..., and ...". The auxiliary names in the docstring need not mat_a is ..., and ...". The auxiliary names in the docstring need not
necessarily correspond to any internal names used in the function body (as necessarily correspond to any internal names used in the function body (as
those are not part of the API). those are not part of the API). If the function uses `yield` (is a
generator), the `Yields:` section should document the object returned by
`next()`, instead of the generator object itself that the call evaluates to.
<a id="doc-function-raises"></a> <a id="doc-function-raises"></a>
[*Raises:*](#doc-function-raises) [*Raises:*](#doc-function-raises)
@ -2057,6 +2197,47 @@ def fetch_smalltable_rows(
""" """
``` ```
<a id="s3.8.3.1-overridden-methods"></a>
<a id="overridden-method-docs"></a>
##### 3.8.3.1 Overridden Methods
A method that overrides a method from a base class does not need a docstring if
it is explicitly decorated with
[`@override`](https://typing-extensions.readthedocs.io/en/latest/#override)
(from `typing_extensions` or `typing` modules), unless the overriding method's
behavior materially refines the base method's contract, or details need to be
provided (e.g., documenting additional side effects), in which case a docstring
with at least those differences is required on the overriding method.
```python
from typing_extensions import override
class Parent:
def do_something(self):
"""Parent method, includes docstring."""
# Child class, method annotated with override.
class Child(Parent):
@override
def do_something(self):
pass
```
```python
# Child class, but without @override decorator, a docstring is required.
class Child(Parent):
def do_something(self):
pass
# Docstring is trivial, @override is sufficient to indicate that docs can be
# found in the base class.
class Child(Parent):
@override
def do_something(self):
"""See base class."""
```
<a id="s3.8.4-comments-in-classes"></a> <a id="s3.8.4-comments-in-classes"></a>
<a id="384-classes"></a> <a id="384-classes"></a>
<a id="comments-in-classes"></a> <a id="comments-in-classes"></a>
@ -2065,8 +2246,8 @@ def fetch_smalltable_rows(
#### 3.8.4 Classes #### 3.8.4 Classes
Classes should have a docstring below the class definition describing the class. Classes should have a docstring below the class definition describing the class.
If your class has public attributes, they should be documented here in an Public attributes, excluding [properties](#properties), should be documented
`Attributes` section and follow the same formatting as a here in an `Attributes` section and follow the same formatting as a
[function's `Args`](#doc-function-args) section. [function's `Args`](#doc-function-args) section.
```python ```python
@ -2090,8 +2271,9 @@ class SampleClass:
self.likes_spam = likes_spam self.likes_spam = likes_spam
self.eggs = 0 self.eggs = 0
def public_method(self): @property
"""Performs operation blah.""" def butter_sticks(self) -> int:
"""The number of butter sticks we have."""
``` ```
All class docstrings should start with a one-line summary that describes what All class docstrings should start with a one-line summary that describes what
@ -2366,7 +2548,7 @@ messages shown to the user) should follow three guidelines:
```python ```python
Yes: Yes:
if not 0 <= p <= 1: if not 0 <= p <= 1:
raise ValueError(f'Not a probability: {p!r}') raise ValueError(f'Not a probability: {p=}')
try: try:
os.rmdir(workdir) os.rmdir(workdir)
@ -2378,7 +2560,7 @@ messages shown to the user) should follow three guidelines:
```python ```python
No: No:
if p < 0 or p > 1: # PROBLEM: also false for float('nan')! if p < 0 or p > 1: # PROBLEM: also false for float('nan')!
raise ValueError(f'Not a probability: {p!r}') raise ValueError(f'Not a probability: {p=}')
try: try:
os.rmdir(workdir) os.rmdir(workdir)
@ -2477,27 +2659,36 @@ documentation must explain clearly how resource lifetime is managed.
Use `TODO` comments for code that is temporary, a short-term solution, or Use `TODO` comments for code that is temporary, a short-term solution, or
good-enough but not perfect. good-enough but not perfect.
A `TODO` comment begins with the word `TODO` in all caps, and a parenthesized A `TODO` comment begins with the word `TODO` in all caps, a following colon, and
context identifier. Ideally a bug reference, sometimes a username. A bug a link to a resource that contains the context, ideally a bug reference. A bug
reference like `TODO(https://crbug.com/bug_id_number):` is reference is preferable because bugs are tracked and have follow-up comments.
preferable, because bugs are tracked and have follow-up comments, whereas Follow this piece of context with an explanatory string introduced with a hyphen
individuals move around and may lose context over time. The `TODO` is followed by an explanation of `-`.
what there is to do.
The purpose is to have a consistent `TODO` format that can be searched to find The purpose is to have a consistent `TODO` format that can be searched to find
out how to get more details. A `TODO` is not a commitment that the person out how to get more details.
referenced will fix the problem. Thus when you create a `TODO` with a username,
it is almost always your *own* username that is given. ```python
# TODO: crbug.com/192795 - Investigate cpufreq optimizations.
```
Old style, formerly recommended, but discouraged for use in new code:
```python ```python
# TODO(crbug.com/192795): Investigate cpufreq optimizations. # TODO(crbug.com/192795): Investigate cpufreq optimizations.
# TODO(yourusername): File an issue and use a '*' for repetition. # TODO(yourusername): Use a "\*" here for concatenation operator.
```
Avoid adding TODOs that refer to an individual or team as the context:
```python
# TODO: @yourusername - File an issue and use a '*' for repetition.
``` ```
If your `TODO` is of the form "At a future date do something" make sure that you If your `TODO` is of the form "At a future date do something" make sure that you
either include a very specific date ("Fix by November 2009") or a very specific either include a very specific date ("Fix by November 2009") or a very specific
event ("Remove this code when all clients can handle XML responses.") that event ("Remove this code when all clients can handle XML responses.") that
future code maintainers will comprehend. future code maintainers will comprehend. Issues are ideal for tracking this.
<a id="s3.13-imports-formatting"></a> <a id="s3.13-imports-formatting"></a>
<a id="313-imports-formatting"></a> <a id="313-imports-formatting"></a>
@ -2722,7 +2913,9 @@ Always use a `.py` filename extension. Never use dashes.
class. class.
- Prepending a single underscore (`_`) has some support for protecting module - Prepending a single underscore (`_`) has some support for protecting module
variables and functions (linters will flag protected member access). variables and functions (linters will flag protected member access). Note
that it is okay for unit tests to access protected constants from the
modules under test.
- Prepending a double underscore (`__` aka "dunder") to an instance variable - Prepending a double underscore (`__` aka "dunder") to an instance variable
or method effectively makes the variable or method private to its class or method effectively makes the variable or method private to its class
@ -2930,13 +3123,20 @@ the function into smaller and more manageable pieces.
* Familiarize yourself with [PEP-484](https://peps.python.org/pep-0484/). * Familiarize yourself with [PEP-484](https://peps.python.org/pep-0484/).
* In methods, only annotate `self`, or `cls` if it is necessary for proper * Annotating `self` or `cls` is generally not necessary.
type information. e.g., [`Self`](https://docs.python.org/3/library/typing.html#typing.Self) can be
used if it is necessary for proper type information, e.g.
```python ```python
from typing import Self
class BaseClass:
@classmethod @classmethod
def create(cls: Type[_T]) -> _T: def create(cls) -> Self:
return cls() ...
def difference(self, other: Self) -> float:
...
``` ```
* Similarly, don't feel compelled to annotate the return value of `__init__` * Similarly, don't feel compelled to annotate the return value of `__init__`
@ -3327,15 +3527,16 @@ return type is the same as the argument type in the code above, use
<a id="typing-imports"></a> <a id="typing-imports"></a>
#### 3.19.12 Imports For Typing #### 3.19.12 Imports For Typing
For symbols from the `typing` and `collections.abc` modules used to support For symbols (including types, functions, and constants) from the `typing` or
static analysis and type checking, always import the symbol itself. This keeps `collections.abc` modules used to support static analysis and type checking,
common annotations more concise and matches typing practices used around the always import the symbol itself. This keeps common annotations more concise and
world. You are explicitly allowed to import multiple specific classes on one matches typing practices used around the world. You are explicitly allowed to
line from the `typing` and `collections.abc` modules. Ex: import multiple specific symbols on one line from the `typing` and
`collections.abc` modules. For example:
```python ```python
from collections.abc import Mapping, Sequence from collections.abc import Mapping, Sequence
from typing import Any, Generic from typing import Any, Generic, cast, TYPE_CHECKING
``` ```
Given that this way of importing adds items to the local namespace, names in Given that this way of importing adds items to the local namespace, names in

View File

@ -5,7 +5,7 @@
# Its canonical open-source location is: # Its canonical open-source location is:
# https://google.github.io/styleguide/pylintrc # https://google.github.io/styleguide/pylintrc
[MASTER] [MAIN]
# Files or directories to be skipped. They should be base names, not paths. # Files or directories to be skipped. They should be base names, not paths.
ignore=third_party ignore=third_party
@ -50,7 +50,8 @@ confidence=
# --enable=similarities". If you want to run only the classes checker, but have # --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes # no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W" # --disable=W"
disable=abstract-method, disable=R,
abstract-method,
apply-builtin, apply-builtin,
arguments-differ, arguments-differ,
attribute-defined-outside-init, attribute-defined-outside-init,
@ -66,7 +67,6 @@ disable=abstract-method,
coerce-method, coerce-method,
delslice-method, delslice-method,
div-method, div-method,
duplicate-code,
eq-without-hash, eq-without-hash,
execfile-builtin, execfile-builtin,
file-builtin, file-builtin,
@ -80,7 +80,6 @@ disable=abstract-method,
import-error, import-error,
import-self, import-self,
import-star-module-level, import-star-module-level,
inconsistent-return-statements,
input-builtin, input-builtin,
intern-builtin, intern-builtin,
invalid-str-codec, invalid-str-codec,
@ -94,10 +93,6 @@ disable=abstract-method,
next-method-called, next-method-called,
next-method-defined, next-method-defined,
no-absolute-import, no-absolute-import,
no-else-break,
no-else-continue,
no-else-raise,
no-else-return,
no-init, # added no-init, # added
no-member, no-member,
no-name-in-module, no-name-in-module,
@ -123,24 +118,12 @@ disable=abstract-method,
standarderror-builtin, standarderror-builtin,
suppressed-message, suppressed-message,
sys-max-int, sys-max-int,
too-few-public-methods,
too-many-ancestors,
too-many-arguments,
too-many-boolean-expressions,
too-many-branches,
too-many-instance-attributes,
too-many-locals,
too-many-nested-blocks,
too-many-public-methods,
too-many-return-statements,
too-many-statements,
trailing-newlines, trailing-newlines,
unichr-builtin, unichr-builtin,
unicode-builtin, unicode-builtin,
unnecessary-pass, unnecessary-pass,
unpacking-in-except, unpacking-in-except,
useless-else-on-loop, useless-else-on-loop,
useless-object-inheritance,
useless-suppression, useless-suppression,
using-cmp-argument, using-cmp-argument,
wrong-import-order, wrong-import-order,
@ -225,7 +208,7 @@ no-docstring-rgx=(__.*__|main|test.*|.*test|.*Test)$
# Minimum line length for functions/classes that require docstrings, shorter # Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt. # ones are exempt.
docstring-min-length=10 docstring-min-length=12
[TYPECHECK] [TYPECHECK]
@ -235,10 +218,6 @@ docstring-min-length=10
# produce valid context managers. # produce valid context managers.
contextmanager-decorators=contextlib.contextmanager,contextlib2.contextmanager contextmanager-decorators=contextlib.contextmanager,contextlib2.contextmanager
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# List of module names for which member attributes should not be checked # List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime # (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It # and thus existing member attributes cannot be deduced by static analysis. It
@ -261,7 +240,7 @@ generated-members=
# Maximum number of characters on a single line. # Maximum number of characters on a single line.
max-line-length=80 max-line-length=80
# TODO(https://github.com/PyCQA/pylint/issues/3352): Direct pylint to exempt # TODO(https://github.com/pylint-dev/pylint/issues/3352): Direct pylint to exempt
# lines made too long by directives to pytype. # lines made too long by directives to pytype.
# Regexp for a line that is allowed to be longer than the limit. # Regexp for a line that is allowed to be longer than the limit.
@ -418,12 +397,3 @@ valid-classmethod-first-arg=cls,
# List of valid names for the first argument in a metaclass class method. # List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=mcs valid-metaclass-classmethod-first-arg=mcs
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "Exception"
overgeneral-exceptions=builtins.StandardError,
builtins.Exception,
builtins.BaseException

View File

@ -7,7 +7,13 @@ body {
margin-left: 100px; margin-left: 100px;
} }
h1, h2, h3, h4, h5, h6, .toc_title { h1,
h2,
h3,
h4,
h5,
h6,
.toc_title {
color: #06c; color: #06c;
margin-top: 2em; margin-top: 2em;
margin-bottom: 1em; margin-bottom: 1em;
@ -18,38 +24,47 @@ h1 {
font-size: 18pt; font-size: 18pt;
} }
h2, .toc_title { h2,
.toc_title {
font-weight: bold; font-weight: bold;
font-size: 12pt; font-size: 12pt;
margin-left: -40px; margin-left: -40px;
} }
h3, h4, h5, h6 { h3,
h4,
h5,
h6 {
font-size: 10pt; font-size: 10pt;
margin-left: -20px; margin-left: -20px;
} }
.toc_category, .toc_stylepoint { .toc_category,
.toc_stylepoint {
font-size: 10pt; font-size: 10pt;
padding-top: .3em; padding-top: 0.3em;
padding-bottom: .3em; padding-bottom: 0.3em;
} }
table { table {
border-collapse: collapse; border-collapse: collapse;
} }
td, th { td,
th {
border: 1px solid #ccc; border: 1px solid #ccc;
padding: 2px 12px; padding: 2px 12px;
font-size: 10pt; font-size: 10pt;
} }
.toc td, .toc th { .toc td,
.toc th {
border-width: 1px 5px; border-width: 1px 5px;
} }
code, samp, var { code,
samp,
var {
color: #060; color: #060;
} }
@ -58,16 +73,9 @@ pre {
display: block; display: block;
color: #060; color: #060;
background-color: #f8fff8; background-color: #f8fff8;
border-color: #f0fff0; border: 1px solid #f0fff0;
border-style: solid;
border-top-width: 1px;
border-bottom-width: 1px;
border-right-width: 1px;
border-left-width: 5px; border-left-width: 5px;
padding-left: 12px; padding: 4px 12px;
padding-right: 12px;
padding-top: 4px;
padding-bottom: 4px;
} }
pre.badcode { pre.badcode {
@ -79,8 +87,7 @@ pre.badcode {
.showhide_button { .showhide_button {
float: left; float: left;
cursor: pointer; cursor: pointer;
border-width: 1px; border: 1px solid;
border-style: solid;
border-color: #ddd #aaa #aaa #ddd; border-color: #ddd #aaa #aaa #ddd;
padding: 0 3px 1px; padding: 0 3px 1px;
margin: 0 4px 8px 0; margin: 0 4px 8px 0;
@ -93,9 +100,7 @@ pre.badcode {
float: left; float: left;
display: none; display: none;
background-color: #f8f8ff; background-color: #f8f8ff;
border-color: #f0f0ff; border: 1px solid #f0f0ff;
border-style: solid;
border-width: 1px;
font-size: 75%; font-size: 75%;
margin-top: 0; margin-top: 0;
margin-left: -50px; margin-left: -50px;
@ -118,7 +123,7 @@ hr {
.stylepoint_section { .stylepoint_section {
display: block; display: block;
margin-bottom: 1em; margin-bottom: 1em;
color: #5588ff; color: #58f;
font-family: sans-serif; font-family: sans-serif;
font-size: 90%; font-size: 90%;
font-weight: bold; font-weight: bold;
@ -126,7 +131,7 @@ hr {
} }
.stylepoint_subsection { .stylepoint_subsection {
color: #667799; color: #679;
font-family: sans-serif; font-family: sans-serif;
font-size: 90%; font-size: 90%;
font-weight: bold; font-weight: bold;
@ -134,7 +139,7 @@ hr {
} }
.stylepoint_subsubsection { .stylepoint_subsubsection {
color: #667799; color: #679;
font-family: sans-serif; font-family: sans-serif;
font-size: 80%; font-size: 80%;
font-weight: bold; font-weight: bold;
@ -144,4 +149,3 @@ hr {
.revision { .revision {
text-align: right; text-align: right;
} }

File diff suppressed because it is too large Load Diff