annotate src/capnproto-git-20161025/style-guide.md @ 157:570d27da3fb5

Update exclusion list
author Chris Cannam <cannam@all-day-breakfast.com>
date Fri, 25 Jan 2019 13:49:22 +0000
parents 1ac99bfc383d
children
rev   line source
cannam@133 1 # KJ Style
cannam@133 2
cannam@133 3 This document describes how to write C++ code in KJ style. It may be compared to the [Google C++ Style Guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.html).
cannam@133 4
cannam@133 5 KJ style is used by KJ (obviously), [Cap'n Proto](https://capnproto.org), [Sandstorm.io](https://sandstorm.io), and possibly other projects. When submitting code to these projects, you should follow this guide.
cannam@133 6
cannam@133 7 **Table of Contents**
cannam@133 8
cannam@133 9 - [Rule #1: There are no rules](#rule-1-there-are-no-rules)
cannam@133 10 - [Design Philosophy](#design-philosophy)
cannam@133 11 - [Value Types vs. Resource Types](#value-types-vs-resource-types)
cannam@133 12 - [RAII (Resource Acquisition Is Initialization)](#raii-resource-acquisition-is-initialization)
cannam@133 13 - [Ownership](#ownership)
cannam@133 14 - [No Singletons](#no-singletons)
cannam@133 15 - [Exceptions](#exceptions)
cannam@133 16 - [Threads vs. Event Loops](#threads-vs-event-loops)
cannam@133 17 - [Lazy input validation](#lazy-input-validation)
cannam@133 18 - [Premature optimization fallacy](#premature-optimization-fallacy)
cannam@133 19 - [Text is always UTF-8](#text-is-always-utf-8)
cannam@133 20 - [C++ usage](#c-usage)
cannam@133 21 - [Use C++11 (or later)](#use-c11-or-later)
cannam@133 22 - [Heap allocation](#heap-allocation)
cannam@133 23 - [Pointers, references](#pointers-references)
cannam@133 24 - [Constness](#constness)
cannam@133 25 - [Inheritance](#inheritance)
cannam@133 26 - [Exceptions Usage](#exceptions-usage)
cannam@133 27 - [Template Metaprogramming](#template-metaprogramming)
cannam@133 28 - [Global Constructors](#global-constructors)
cannam@133 29 - [`dynamic_cast`](#dynamic_cast)
cannam@133 30 - [Use of Standard libraries](#use-of-standard-libraries)
cannam@133 31 - [Compiler warnings](#compiler-warnings)
cannam@133 32 - [Tools](#tools)
cannam@133 33 - [Irrelevant formatting rules](#irrelevant-formatting-rules)
cannam@133 34 - [Naming](#naming)
cannam@133 35 - [Spacing and bracing](#spacing-and-bracing)
cannam@133 36 - [Comments](#comments)
cannam@133 37 - [File templates](#file-templates)
cannam@133 38
cannam@133 39 ## Rule #1: There are no rules
cannam@133 40
cannam@133 41 This guide contains suggestions, not rules.
cannam@133 42
cannam@133 43 If you wish to submit code to a project following KJ style, you should follow the guide so long as there is no good reason not to. You should not break rules just because you feel like it -- consistency is important for future maintainability. But, if you have a good, pragmatic reason to break a rule, do it. Do not ask permission. Just do it.
cannam@133 44
cannam@133 45 ## Design Philosophy
cannam@133 46
cannam@133 47 This section contains guidelines on software design that aren't necessarily C++-specific (though KJ's preferences here are obviously influenced by C++).
cannam@133 48
cannam@133 49 ### Value Types vs. Resource Types
cannam@133 50
cannam@133 51 There are two kinds of types: values and resources. Value types are simple data structures; they serve no purpose except to represent pure data. Resource types represent live objects with state and behavior, and often represent resources external to the program.
cannam@133 52
cannam@133 53 * Value types make sense to copy (though they don't necessarily have copy constructors). Resource types are not copyable.
cannam@133 54 * Value types always have move constructors (and sometimes copy constructors). Resource types are not movable; if ownership transfer is needed, the resource must be allocated on the heap.
cannam@133 55 * Value types almost always have implicit destructors. Resource types may have an explicit destructor.
cannam@133 56 * Value types should only be compared by value, not identity. Resource types can only be compared by identity.
cannam@133 57 * Value types make sense to serialize. Resource types fundamentally cannot be serialized.
cannam@133 58 * Value types rarely use inheritance and never have virtual methods. Resource types commonly do.
cannam@133 59 * Value types generally use templates for polymorphism. Resource types generally use virtual methods / abstract interfaces.
cannam@133 60 * You might even say that value types are used in functional programming style while resource types are used in object-oriented style.
cannam@133 61
cannam@133 62 In Cap'n Proto there is a very clear distinction between values and resources: interfaces are resource types whereas everything else is a value.
cannam@133 63
cannam@133 64 ### RAII (Resource Acquisition Is Initialization)
cannam@133 65
cannam@133 66 KJ code is RAII-strict. Whenever it is the case that "this block of code cannot exit cleanly without performing operation X", then X *must* be performed in a destructor, so that X will happen regardless of how the block is exited (including by exception).
cannam@133 67
cannam@133 68 Use the macros `KJ_DEFER`, `KJ_ON_SCOPE_SUCCESS`, and `KJ_ON_SCOPE_FAILURE` to easily specify some code that must be executed on exit from the current scope, without the need to define a whole class with a destructor.
cannam@133 69
cannam@133 70 Be careful when writing complicated destructors. If a destructor performs multiple cleanup actions, you generally need to make sure that the latter actions occur even if the former ones throw an exception. For this reason, a destructor should generally perform no more than one cleanup action. If you need to clean up multiple things, have you class contain multiple members representing the different things that need cleanup, each with its own destructor. This way, if one member's destructor throws, the others still run.
cannam@133 71
cannam@133 72 ### Ownership
cannam@133 73
cannam@133 74 Every object has an "owner". The owner may be another object, or it may be a stack frame (which is in turn owned by its parent stack frame, and so on up to the top frame, which is owned by the thread, which itself is an object which is owned by something).
cannam@133 75
cannam@133 76 The owner decides when to destroy an object. If the owner itself is destroyed, everything it owns must be transitively destroyed. This should be accomplished through RAII style.
cannam@133 77
cannam@133 78 The owner specifies the lifetime of the object and how the object may be accessed. This specification may be through documented convention or actually enforced through the type system; the latter is preferred when possible.
cannam@133 79
cannam@133 80 An object can never own itself, including transitively.
cannam@133 81
cannam@133 82 When declaring a pointer to an object which is owned by the scope, always use `kj::Own<T>`. Regular C++ pointers and references always point to objects that are *not* owned.
cannam@133 83
cannam@133 84 When passing a regular C++ pointer or reference as a parameter or return value of a function, care must be taken to document assumptions about the lifetime of the object. In the absence of documentation, make the following assumptions:
cannam@133 85
cannam@133 86 * A pointer or reference passed as a constructor parameter must remain valid for the lifetime of the constructed object.
cannam@133 87 * A pointer or reference passed as a function or method parameter must remain valid until the function returns. In the case that the function returns a promise, then the object must remain live until the promise completes or is canceled.
cannam@133 88 * A pointer or reference returned by a method remains valid at least until the object whose method was called is destroyed.
cannam@133 89 * A pointer or reference returned by a stand-alone function likely refers to content of one of the function's parameters, and remains valid until that parameter is destroyed.
cannam@133 90
cannam@133 91 Note that ownership isn't just about memory management -- it matters even in languages that implement garbage collection! Unless an object is 100% immutable, you need to keep track of who is allowed to modify it, and that generally requires declaring an owner. Moreover, even with GC, resource types commonly need `close()` method that acts very much like a C++ destructor, leading to all the same considerations. It is therefore completely wrong to believe garbage collection absolves you of thinking about ownership -- and this misconception commonly leads to huge problems in large-scale systems written in GC languages.
cannam@133 92
cannam@133 93 #### Reference Counting
cannam@133 94
cannam@133 95 Reference counting is allowed, in which case an object will have multiple owners.
cannam@133 96
cannam@133 97 When using reference counting, care must be taken to ensure that there is a clear contract between all owners about how the object shall be accessed. In general, this should mean one of the following:
cannam@133 98
cannam@133 99 * Reference-counted value types should be immutable.
cannam@133 100 * Reference-counted resource types should have an interface which clearly specifies how multiple clients should coordinate.
cannam@133 101
cannam@133 102 Care must also be taken to avoid cyclic references (which would constitute self-ownership, and would cause a memory leak). Think carefully about what the object ownership graph looks like.
cannam@133 103
cannam@133 104 Avoid reference counting when it is not absolutely necessary.
cannam@133 105
cannam@133 106 Keep in mind that atomic (thread-safe) reference counting can be extremely slow. Consider non-atomic reference counting if it is feasible under your threading philosophy (under KJ's philosophy, non-atomic reference counting is OK).
cannam@133 107
cannam@133 108 ### No Singletons
cannam@133 109
cannam@133 110 A "singleton" is any mutable object or value that is globally accessible. "Globally accessible" means that the object is declared as a global variable or static member variable, or that the object can be found by following pointers from such variables.
cannam@133 111
cannam@133 112 Never use singletons. Singletons cause invisible and unexpected dependencies between components of your software that appear unrelated. Worse, the assumption that "there should only be one of this object per process" is almost always wrong, but its wrongness only becomes apparent after so much code uses the singleton that it is infeasible to change. Singleton interfaces ofter turn into unusable monstrosities in an attempt to work around the fact that they should never have been a singleton in the first place.
cannam@133 113
cannam@133 114 See ["Singletons Considered Harmful"](http://www.object-oriented-security.org/lets-argue/singletons) for a complete discussion.
cannam@133 115
cannam@133 116 #### Global registries are singletons
cannam@133 117
cannam@133 118 An all-too-common-pattern in modular frameworks is to design a way to register named components via global-scope macros. For example:
cannam@133 119
cannam@133 120 // BAD BAD BAD
cannam@133 121 REGISTER_PLUGIN("foo", fooEntryPoint);
cannam@133 122
cannam@133 123 This global registry is a singleton, and has many of the same problems as singletons. Don't do this. Again, see ["Singletons Considered Harmful"](http://www.object-oriented-security.org/lets-argue/singletons) for discussion.
cannam@133 124
cannam@133 125 #### What to do instead
cannam@133 126
cannam@133 127 High-level code (such as your `main()` function) should explicitly initialize the components the program needs. If component Foo depends on component Bar, then Foo's constructor should take a pointer to Bar as a parameter; the high-level code can then point each component at its dependencies explicitly.
cannam@133 128
cannam@133 129 For example, instead of a global registry, have high-level code construct a registry object and explicitly call some `register()` method to register each component that should be available through it. This way, when you read your `main()` function it's easy to see what components your program is using.
cannam@133 130
cannam@133 131 #### Working around OS singletons
cannam@133 132
cannam@133 133 Unfortunately, operating system APIs are traditionally singleton-heavy. The most obvious example is, of course, the filesystem.
cannam@133 134
cannam@133 135 In order to use these APIs while avoiding the problems of singletons, try to encapsulate OS singletons inside non-singleton interfaces as early on as possible in your program. For example, you might define an abstract interface called `Directory` with an implementation `DiskDirectory` representing a directory on disk. In your `main()` function, create two `DiskDirectory`s representing the root directory and the current working directory. From then on, have all of your code operate in terms of `Directory`. Pass the original `DiskDirectory` pointers into the components that need it.
cannam@133 136
cannam@133 137 ### Exceptions
cannam@133 138
cannam@133 139 An exception represents something that "should never happen", assuming everything is working as expected. Of course, things that "should never happen" in fact happen all the time. But, a program should never be written in such a way that it _expects_ an exception under normal circumstances.
cannam@133 140
cannam@133 141 Put another way, exceptions are a way to achieve _fault tolerance_. Throwing an exception is a less-disruptive alternative to aborting the process. Exceptions are a _logistical_ construct, as opposed to a semantic one: an exception should never be part of your "business logic".
cannam@133 142
cannam@133 143 For example, exceptions may indicate conditions like:
cannam@133 144
cannam@133 145 * Logistics of software development:
cannam@133 146 * There is a bug in the code.
cannam@133 147 * The requested method is not implemented.
cannam@133 148 * Logistics of software usage:
cannam@133 149 * There is an error in the program's configuration.
cannam@133 150 * The input is invalid.
cannam@133 151 * Logistics of distributed systems:
cannam@133 152 * A network connection was reset.
cannam@133 153 * An optimistic transaction was aborted due to concurrent modification.
cannam@133 154 * Logistics of physical computation:
cannam@133 155 * The system's resources are exhausted (e.g. out of memory, out of disk space).
cannam@133 156 * The system is overloaded and must reject some requests to avoid long queues.
cannam@133 157
cannam@133 158 #### Business logic should never catch
cannam@133 159
cannam@133 160 If you find that callers of your interface need to catch and handle certain kinds of exceptions in order to operate correctly, then you must change your interface (or overload it) such that those conditions can be handled without an exception ever being thrown. For example, if you have a method `Own<File> open(StringPtr name)` that opens a file, you may also want to offer `Maybe<Own<File>> openIfExists(StringPtr name)` that returns null rather than throwing an exception if the file is not found. (But you should probably keep `open()` as well, for the convenience of the common case where the caller will just throw an exception anyway.)
cannam@133 161
cannam@133 162 Note that with this exception philosophy, Java-style "checked exceptions" (exceptions which are explicitly declared to be thrown by an interface) make no sense.
cannam@133 163
cannam@133 164 #### How to handle an exception
cannam@133 165
cannam@133 166 In framework and logistical code, you may catch exceptions and try to handle them. Given the nature of exceptions, though, there are only a few things that are reasonable to do when receiving an exception:
cannam@133 167
cannam@133 168 * On network disconnect or transaction failures, back up and start over from the beginning (restore connections and state, redo operations).
cannam@133 169 * On resources exhausted / overloaded, retry again later, with exponential back-off.
cannam@133 170 * On unimplemented methods, retry with a different implementation strategy, if there is one.
cannam@133 171 * When no better option is available, report the problem to a human (the user and/or the developer).
cannam@133 172
cannam@133 173 #### Exceptions can happen anywhere (including destructors)
cannam@133 174
cannam@133 175 Any piece of code may contain a bug. Therefore, an exception can happen anywhere. This includes destructors. It doesn't matter how much you argue that destructors should not throw exceptions, because that is equivalent to arguing that code should not have bugs. We all wish our code never had bugs, but nevertheless it happens.
cannam@133 176
cannam@133 177 Unfortunately, C++ made the awful decision that an exception thrown from a destructor that itself is called during stack unwind due to some other exception should cause the process to abort. This is an error in the language specification. Apparently, the committee could not agree on any other behavior, so they chose the worst possible behavior.
cannam@133 178
cannam@133 179 If exceptions are merely a means to fault tolerance, then it is perfectly clear what should happen in the case that a second exception is thrown while unwinding due to a first: the second exception should merely be discarded, or perhaps attached to the first as a supplementary note. The catching code usually does not care about the exception details anyway; it's just going to report that something went wrong, then maybe try to continue executing other, unrelated parts of the program. In fact, in most cases discarding the secondary exception makes sense, because it is often simply a side-effect of the fact that the code didn't complete normally, and so provides no useful additional information.
cannam@133 180
cannam@133 181 Alas, C++ is what it is. So, in KJ, we work around the problem in a couple ways:
cannam@133 182
cannam@133 183 * `kj::UnwindDetector` may be used to detect when a destructor is called during unwind and squelch secondary exceptions.
cannam@133 184 * The `KJ_ASSERT` family of macros -- from which most exceptions are thrown in the first place -- implement a concept of "recoverable" exceptions, where it is safe to continue execution without throwing in cases where throwing would be bad. Assert macros in destructors must always be recoverable.
cannam@133 185
cannam@133 186 #### Allowing `-fno-exceptions`
cannam@133 187
cannam@133 188 KJ and Cap'n Proto are designed to function even when compiled with `-fno-exceptions`. In this case, throwing an exception behaves differently depending on whether the exception is "fatal" or "recoverable". Fatal exceptions abort the process. On a recoverable exception, on the other hand, execution continues normally, perhaps after replacing invalid data with some safe default. The exception itself is stored in a thread-local variable where code up the stack can check for it later on.
cannam@133 189
cannam@133 190 This compromise is made only so that C++ applications which eschew exceptions are still able to use Cap'n Proto. We do NOT recommend disabling exceptions if you have a choice. Moreover, code following this style guide (other than KJ and Cap'n Proto) is not required to be `-fno-exceptions`-safe, and in fact we recommend against it.
cannam@133 191
cannam@133 192 ### Threads vs. Event Loops
cannam@133 193
cannam@133 194 Threads are hard, and synchronization between threads is slow. Even "lock-free" data structures usually require atomic operations, which are costly, and such algorithms are notoriously difficult to get right. Fine-grained synchronization will therefore be expensive at best and highly unstable at worst.
cannam@133 195
cannam@133 196 KJ instead prefers event loop concurrency. In this model, each event callback is effectively a transaction; it does not need to worry about concurrent modification within the body of the function.
cannam@133 197
cannam@133 198 Multiple threads may exist, but each one has its own event loop and is treated as sort of a lightweight process with shared memory. Every object in the process either belongs to a specific thread (who is allowed to read and modify it) or is transitively immutable (in which case all threads can safely read it concurrently). Threads communicate through asynchronous message-passing. In fact, the only big difference between KJ-style threads compared to using separate processes is that threads may transfer ownership of in-memory objects as part of a message send.
cannam@133 199
cannam@133 200 Note that with hardware transactional memory, it may become possible to execute a single event loop across multiple CPU cores while behaving equivalently to a single thread, by executing each event callback as a hardware transaction. If so, this will be implemented as part of KJ's event loop machinery, transparently to apps.
cannam@133 201
cannam@133 202 ### Lazy input validation
cannam@133 203
cannam@133 204 As we all know, you should always validate your input.
cannam@133 205
cannam@133 206 But, when should you validate it? There are two plausible answers:
cannam@133 207
cannam@133 208 * Upfront, on receipt.
cannam@133 209 * Lazily, on use.
cannam@133 210
cannam@133 211 Upfront validation occasionally makes sense for the purpose of easier debugging of problems: if an error is reported earlier, it's easier to find where it came from.
cannam@133 212
cannam@133 213 However, upfront validation has some big problems.
cannam@133 214
cannam@133 215 * It is inefficient, as it requires a redundant pass over the data. Lazy validation, in contrast, occurs at a time when you have already loaded the data for the purpose of using it. Extra passes are often cache-unfriendly and/or entail redundant I/O operations.
cannam@133 216
cannam@133 217 * It encourages people to skip validation at time of use, on the assumption that it was already validated earlier. This is dangerous, as it entails a non-local assumption. E.g. are you really sure that there is no way to insert data into your database without having validated it? Are you really sure that the data hasn't been corrupted? Are you really sure that your code will never be called in a new situation where validation hasn't happened? Are you sure the data cannot have been modified between validation and use? In practice, you should be validating your input at time of use _even if_ you know it has already been checked previously.
cannam@133 218
cannam@133 219 * The biggest problem: Upfront validation tends not to match actual usage, because the validation site is far away from the usage site. Over time, as the usage code changes, the validator can easily get out-of-sync. Note that this could mean the code itself is out-of-sync, or it could be that running servers are out-of-sync, because they have different update schedules. Or, the validator may be written with incorrect assumptions in the first place. The consequences of this can be severe. Protocol Buffers' concept of "required fields" is essentially an upfront validation check that [has been responsible for outages of Google Search, GMail, and others](https://capnproto.org/faq.html#how-do-i-make-a-field-required-like-in-protocol-buffers).
cannam@133 220
cannam@133 221 We recommend, therefore, that validation occur at time of use. Code should be written to be tolerant of validation failures. For example, most code dealing with UTF-8 text should treat it as a blob of bytes, not worrying about invalid byte sequences. When you actually need to decode the code points -- such as to display them -- you should do something reasonable with invalid sequences -- such as display the Unicode replacement character.
cannam@133 222
cannam@133 223 With that said, when storing data in a database long-term, it can make sense to perform an additional validation check at time of storage, in order to more directly notify the caller that their input was invalid. This validation should be considered optional, since the data will be validated again when it is read from storage and used.
cannam@133 224
cannam@133 225 ### Premature optimization fallacy
cannam@133 226
cannam@133 227 _"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil."_ -- Donald Knuth
cannam@133 228
cannam@133 229 _"The improvement in speed from Example 2 to Example 2a is only about 12%, and many people would pronounce that insignificant. The conventional wisdom shared by many of today’s software engineers calls for ignoring efficiency in the small; but I believe this is simply an overreaction to the abuses they see being practiced by penny-wise- and-pound-foolish programmers, who can’t debug or maintain their “optimized” programs. In established engineering disciplines a 12% improvement, easily obtained, is never considered marginal; and I believe the same viewpoint should prevail in software engineering. Of course I wouldn’t bother making such optimizations on a one-shot job, but when it’s a question of preparing quality programs, I don’t want to restrict myself to tools that deny me such efficiencies."_ -- Donald Knuth, **in the same paper**.
cannam@133 230
cannam@133 231 (Credit: [Stop Misquoting Donald Knuth!](http://www.joshbarczak.com/blog/?p=580))
cannam@133 232
cannam@133 233 You should not obsess over optimization or write unmaintainable code for the sake of speed.
cannam@133 234
cannam@133 235 However, you _should_ be thinking about efficiency of all the code you write. When writing efficient code is not much harder and not much uglier than inefficient code, you should be writing efficient code. If the efficient approach to a problem would take _much_ longer than the inefficient way then go ahead and code the inefficient way first, but in many cases it's not that stark. Rewriting your code later is _much_ more expensive than writing it correctly the first time, because by then you'll have lost context.
cannam@133 236
cannam@133 237 You should be constantly aware of whether the code you are writing is low-level (called frequently) or high-level (called infrequently). You should consider optimizations relative to the code's level. In low-level code, optimizations like avoiding heap allocations may make sense. In high-level code you should not worry about heap, but you may still want to think about expensive operations like disk I/O or contacting remote servers (things that low-level code should never do in the first place, of course).
cannam@133 238
cannam@133 239 Programmers who ignore efficiency until they have no choice inevitably end up shipping slow, bloated software. Their code's speed is always pushing the boundary of bearability, because they only do anything about it when it becomes unbearable. But programs which are "bearable" can still make users intensely unhappy due to their slowness.
cannam@133 240
cannam@133 241 ### Text is always UTF-8
cannam@133 242
cannam@133 243 Always encode text as UTF-8. Always assume text is encoded as UTF-8.
cannam@133 244
cannam@133 245 (Do not, however, assume text is _valid_ UTF-8; see the section on lazy validation.)
cannam@133 246
cannam@133 247 Do not write code that tries to distinguish characters. Unless you are writing code to render text to a display, you probably don't care about characters. Besides, Unicode itself contains code points which act as modifiers to previous characters; it's futile for you to handle these. Most code only really cares about bytes.
cannam@133 248
cannam@133 249 Note that even parsers for machine-readable text-based languages (config languages, programming languages, other DSLs) do not really care about "characters" in the Unicode sense because such languages are almost always pure-ASCII. They may allow arbitrary UTF-8 in, say, string literals, but only ASCII code points have any special meaning to the language. Therefore, they still only care about bytes (since ASCII characters are single-byte, and multi-byte UTF-8 codepoints never contain individual bytes in the ASCII range).
cannam@133 250
cannam@133 251 ## C++ usage
cannam@133 252
cannam@133 253 This section contains guidelines for usage of C++ language features.
cannam@133 254
cannam@133 255 ### Use C++11 (or later)
cannam@133 256
cannam@133 257 C++11 completely transformed the way the C++ language is used. New code should take heavy advantage of the new features, especially rvalue references (move semantics) and lambda expressions.
cannam@133 258
cannam@133 259 KJ requires C++11. Application code (not used as a library) may consider requiring C++14, or even requiring a specific compiler and tracking the latest language features implemented by it.
cannam@133 260
cannam@133 261 ### Heap allocation
cannam@133 262
cannam@133 263 * Never write `new` or `delete` explicitly. Use `kj::heap` to allocate single objects or `kj::heapArray` for arrays; these return "owned" pointers (`kj::Own<T>` or `kj::Array<T>`, respectively) which enforce RAII/ownership semantics. You may transfer ownership of these pointers via move semantics, but otherwise the objects will be automatically deleted when they go out of scope. This makes memory leaks very rare in KJ code.
cannam@133 264 * Only allocate objects on the heap when you actually need to be able to move them. Otherwise, avoid a heap allocation by declaring the object directly on the stack or as a member of some other object.
cannam@133 265 * If a class's copy constructor would require memory allocation, consider providing a `clone()` method instead and deleting the copy constructor. Allocation in implicit copies is a common source of death-by-1000-cuts performance problems. `kj::String`, for example, is movable but not copyable.
cannam@133 266
cannam@133 267 ### Pointers, references
cannam@133 268
cannam@133 269 * Pointers and references always point to things that are owned by someone else. Take care to think about the lifetime of that object compared to the lifetime of the pointer.
cannam@133 270 * Always use `kj::ArrayPtr<T>` rather than `T*` to point to an array.
cannam@133 271 * Always use `kj::StringPtr` rather than `const char*` to point to a NUL-terminated string.
cannam@133 272 * Always use `kj::Maybe<T&>` rather than `T*` when a pointer can be null. This forces the user to check for null-ness.
cannam@133 273 * In other cases, prefer references over pointers. Note, though, that members of an assignable type cannot be references, so you'll need to use pointers in that case (darn).
cannam@133 274
cannam@133 275 **Rationale:** There is an argument that says that references should always be const and pointers mutable, because then when you see `foo(&bar)` you know that the function modifies `bar`. This is a nice theory, but in practice real C++ code is rarely so consistent that you can use this as a real signal. We prefer references because they make it unambiguous that the value cannot be null.
cannam@133 276
cannam@133 277 ### Constness
cannam@133 278
cannam@133 279 * Treat `const`-ness as transitive. So, if you have a const instance of a struct which in turn contains a pointer (or reference), treat that pointer as pointing to const even if it is not declared as such. To enforce this, copyable classes which contain pointer fields should declare their copy constructor as `T(T& other)` rather than `T(const T& other)` (and similarly for assignment operators) in order to prevent escalating a transitively-const pointer to non-const via copy. You may inherit `kj::DisallowConstCopy` to force the implicit copy constructor and assignment operator to be declared this way.
cannam@133 280 * Try to treat const/non-const pointers like shared/exclusive locks. So, when a new const pointer to an object is created, all other pointers should also be considered const at least until the new pointer is destroyed. When a new non-const pointer is created, all other pointers should be considered not dereferenceable until the non-const pointer is destroyed. In theory, these rules help keep different objects from interfering with each other by modifying some third object in incompatible ways. Note that these rules are (as I understand it) enforceable by the Rust type system.
cannam@133 281 * `const` methods are safe to call on the same object from multiple threads simultaneously. Conversely, it is unsafe to call a non-`const` method if any other thread might be calling methods on that object concurrently. Note that KJ defines synchronization primitives including `kj::Mutex` which integrate nicely with this rule.
cannam@133 282
cannam@133 283 ### Inheritance
cannam@133 284
cannam@133 285 A class is either an interface or an implementation. Interfaces have no fields. Implementations have no non-final virtual methods. You should not mix these: a class with state should never have virtual methods, as this leads to fragile base class syndrome.
cannam@133 286
cannam@133 287 Interfaces should NOT declare a destructor, because:
cannam@133 288
cannam@133 289 * That destructor is never called anyway (because we don't use `delete`, and `kj::Own` has a different mechanism for dispatching the destructor).
cannam@133 290 * Declaring destructors for interfaces is tedious.
cannam@133 291 * If you declare a destructor but do not declare it `noexcept(false)`, C++11 will (regrettably) decide that it is `noexcept` and that all derived classes must also have a `noexcept` destructor, which is wrong. (See the exceptions philosophy section for discussion on exceptions in destructors.)
cannam@133 292
cannam@133 293 Multiple inheritance is allowed and encouraged, keeping in mind that you are usually inheriting interfaces.
cannam@133 294
cannam@133 295 You should think carefully about whether to use virtual inheritance; it's not often needed, and it is relatively inefficient, but in complex inheritance hierarchies it becomes critical.
cannam@133 296
cannam@133 297 Implementation inheritance (that is, inheriting an implementation class) is allowed as a way to compose classes without requiring extra allocations. For example, Cap'n Proto's `capnp::InputStreamMessageReader` implements the `capnp::MessageReader` interface by reading from a `kj::InputStream`, which is itself an interface. One implementation of `kj::InputStream` is `kj::FdInputStream`, which reads from a unix file descriptor. As a convenience, Cap'n Proto defines `capnp::StreamFdMessageReader` which multiply-inherits `capnp::InputStreamMessageReader` and `kj::FdInputStream` -- that is, it inherits two implementations, and even inherits the latter privately. Many style guides would consider this taboo. The benefit, though, is that people can declare this composed class on the stack as one unit, with no heap allocation, and end up with something that they can directly treat as a `capnp::MessageReader`; any other solution would lose one of these benefits.
cannam@133 298
cannam@133 299 ### Exceptions Usage
cannam@133 300
cannam@133 301 KJ's exception philosophy is described earlier in this document. Here we describe only how to actually use exceptions in code.
cannam@133 302
cannam@133 303 Never use `throw` explicitly. Almost all exceptions should originate from the `KJ_ASSERT`, `KJ_REQUIRE`, and `KJ_SYSCALL` macros (see `kj/debug.h`). These macros allow you to easily attach useful debug information to the exception message without spending time on string formatting.
cannam@133 304
cannam@133 305 Never declare anything `noexcept`. As explained in the philosophy section, whether you like it or not, bugs can happen anywhere and therefore exceptions can happen anywhere. `noexcept` causes the process to abort on exceptions. Aborting is _never_ the right answer.
cannam@133 306
cannam@133 307 Explicit destructors must always be declared `noexcept(false)`, to work around C++11's regrettable decision that destructors should be `noexcept` by default. In destructors, always use `kj::UnwindDetector` or make all your asserts recoverable in order to ensure that an exception is not thrown during unwind.
cannam@133 308
cannam@133 309 Do not fret too much about recovering into a perfectly consistent state after every exception. That's not the point. The point is to be able to recover at all -- to _improve_ reliability, but not to make it perfect. So, write your code to do a reasonable thing in most cases.
cannam@133 310
cannam@133 311 For example, if you are implementing a data structure like a vector, do not worry about whether move constructors might throw. In practice, it is extraordinarily rare for move constructors to contain any code that could throw. So just assume they don't. Do NOT do what the C++ standard library does and require that all move constructors be explicitly `noexcept`, because people will not remember to mark their move constructors `noexcept`, and you'll just be creating a huge headache for everyone with _no practical benefit_.
cannam@133 312
cannam@133 313 ### Template Metaprogramming
cannam@133 314
cannam@133 315 #### Reducing Verbosity
cannam@133 316
cannam@133 317 Before C++11, it was common practice to write "template functions" in the form of a templated struct which contained a single member representing the output of the function. For example, you might see `std::is_integral<int>::value` to check if `int` is integral. This pattern is excessively verbose, especially when composed into complex expressions.
cannam@133 318
cannam@133 319 In C++11, we can do better. Where before you would have declared a struct named `Foo<T>` with a single member as described above, in C++11 you should:
cannam@133 320
cannam@133 321 1. Define the struct as before, but with the name `Foo_<T>`.
cannam@133 322 2. Define a template `Foo<T>` which directly aliases the single member of `Foo_<T>`. If the output is a type, use a template `using`, whereas if the output is a value, use a `constexpr` function.
cannam@133 323
cannam@133 324 Example:
cannam@133 325
cannam@133 326 template <typename T> struct IsConst_ { static constexpr bool value = false; };
cannam@133 327 template <typename T> struct IsConst_<const T> { static constexpr bool value = true; };
cannam@133 328 template <typename T> constexpr bool isConst() { return IsConst_<T>::value; }
cannam@133 329 // Return true if T is const.
cannam@133 330
cannam@133 331 Or:
cannam@133 332
cannam@133 333 template <typename T> struct UnConst_ { typedef T Type; };
cannam@133 334 template <typename T> struct UnConst_<const T> { typedef T Type; };
cannam@133 335 template <typename T> using UnConst = typename UnConst_<T>::Type;
cannam@133 336 // If T is const, return the underlying non-const type.
cannam@133 337 // Otherwise, just return T.
cannam@133 338
cannam@133 339 Now people can use your template metafunction without the pesky `::Type` or `::value` suffix.
cannam@133 340
cannam@133 341 #### Other hints
cannam@133 342
cannam@133 343 * To explicitly disable a template under certain circumstances, bind an unnamed template parameter to `kj::EnableIf`:
cannam@133 344
cannam@133 345 template <typename T, typename = kj::EnableIf(!isConst<T>())>
cannam@133 346 void mutate(T& ptr);
cannam@133 347 // T must not be const.
cannam@133 348
cannam@133 349 * Say you're writing a template type with a constructor function like so:
cannam@133 350
cannam@133 351 template <typename T>
cannam@133 352 Wrapper<T> makeWrapper(T&& inner);
cannam@133 353 // Wraps `inner` and returns the wrapper.
cannam@133 354
cannam@133 355 Should `inner` be taken by reference or by value here? Both might be useful, depending on the use case. The right answer is actually to support both: if the input is an lvalue, take it by reference, but if it's an rvalue, take it by value (move). And as it turns out, if you write your declaration exactly as shown above, this is exactly what you get, because if the input is an lvalue, `T` will implicitly bind to a reference type, whereas if the input is an rvalue or rvalue reference, T will not be a reference.
cannam@133 356
cannam@133 357 In general, you should assume KJ code in this pattern uses this rule, so if you are passing in an lvalue but don't actually want it wrapped by reference, wrap it in `kj::mv()`.
cannam@133 358
cannam@133 359 * Never use function or method pointers. Prefer templating across functors (like STL does), or for non-templates use `kj::Function` (which will handle this for you).
cannam@133 360
cannam@133 361 ### Global Constructors
cannam@133 362
cannam@133 363 Do not declare global or static variables with dynamic constructors. Global constructors disproportionately hurt startup time because they force code to be paged in before it is really needed. They also are usually only needed by singletons, which you should not be using in general (see philosophy section).
cannam@133 364
cannam@133 365 You can have global constants of non-trivial class type as long as they are declared `constexpr`. If you want to declare complex data structures as constants, try to declare all the pieces as separate globals that reference each other, so that nothing has to be heap allocated and everything can be `constexpr`.
cannam@133 366
cannam@133 367 Use Clang's `-Wglobal-constructors` warning to catch mistakes.
cannam@133 368
cannam@133 369 ### `dynamic_cast`
cannam@133 370
cannam@133 371 Do not use `dynamic_cast` as a way to implement polymorphism. That is, do not write long blocks of if/else statements each trying to cast an object to a different derived class to handle in a different way. Instead, extend the base class's interface to cover the functionality you need.
cannam@133 372
cannam@133 373 With that said, `dynamic_cast` is not always bad. It is fine to use `dynamic_cast` for "logistical" improvements, such as optimization. As a rule of thumb, imagine if `dynamic_cast` were replaced with a function that always returned null. Would your code still be correct (if, perhaps, slower, or with less detailed logging, etc.)? If so, then your use of `dynamic_cast` is fine.
cannam@133 374
cannam@133 375 #### `-fno-rtti`
cannam@133 376
cannam@133 377 The KJ and Cap'n Proto libraries are designed to function correctly when compiled with `-fno-rtti`. To that end, `kj::dynamicCastIfAvailable` is a version of `dynamic_cast` that, when compiled with `-fno-rtti`, always returns null, and KJ and Cap'n Proto code always uses this version.
cannam@133 378
cannam@133 379 We do NOT recommend disabling RTTI in your own code.
cannam@133 380
cannam@133 381 ### Lambdas
cannam@133 382
cannam@133 383 Lamba capture lists must never use `=` to specify "capture all by value", because this makes it hard to review the capture list for possible lifetime issues.
cannam@133 384
cannam@133 385 Capture lists *may* use `&` ("capture all by reference") but *only* in cases where it is known that the lambda will not outlive the current stack frame. In fact, they generally *should* use `&` in this case, to make clear that there are no lifetime issues to think about.
cannam@133 386
cannam@133 387 ### Use of Standard libraries
cannam@133 388
cannam@133 389 #### C++ Standard Library
cannam@133 390
cannam@133 391 The C++ standard library is old and full of a lot of cruft. Many APIs are designed in pre-C++11 styles that are no longer ideal. Mistakes like giving copy constructors to objects that own heap space (because in the absence of move semantics, it was needed for usability) and atomically-reference-counted strings (intended as an optimization to avoid so much heap copying, but actually a pessimization) are now baked into the library and cannot change. The `iostream` library was designed before anyone knew how to write good C++ code and is absolutely awful by today's standards. Some parts of the library, such as `<chrono>`, are over-engineered, designed by committees more interested in theoretical perfection than practicality. To add insult to injury, the library's naming style does not distinguish types from values.
cannam@133 392
cannam@133 393 For these reasons and others, KJ aims to be a replacement for the C++ standard libraries.
cannam@133 394
cannam@133 395 It is not there yet. As of this writing, the biggest missing piece is that KJ provides no implementation of maps or sets, nor a `sort()` function.
cannam@133 396
cannam@133 397 We recommend that KJ code use KJ APIs where available, falling back to C++ standard types when necessary. To avoid breaking clients later, avoid including C++ standard library headers from other headers; only include them from source files.
cannam@133 398
cannam@133 399 All users of the KJ library should familiarize themselves at least with the declarations in the following files, as you will use them all the time:
cannam@133 400
cannam@133 401 * `kj/common.h`
cannam@133 402 * `kj/memory.h`
cannam@133 403 * `kj/array.h`
cannam@133 404 * `kj/string.h`
cannam@133 405 * `kj/vector.h`
cannam@133 406 * `kj/debug.h`
cannam@133 407
cannam@133 408 #### C Library
cannam@133 409
cannam@133 410 As a general rule of thumb, C library functions documented in man section 3 should be treated with skepticism.
cannam@133 411
cannam@133 412 Do not use the C standard I/O functions -- your code should never contain `FILE*`. For formatting strings, `kj::str()` is much safer and easier than `sprintf()`. For debug logging, `KJ_DBG()` will produce more information with fewer keystrokes compared to `printf()`. For parsing, KJ's parser combinator library is cleaner and more powerful than `scanf()`. `fread()` and `fwrite()` imply buffering that you usually don't want; use `kj/io.h` instead, or raw file descriptors.
cannam@133 413
cannam@133 414 ### Compiler warnings
cannam@133 415
cannam@133 416 Use the following warning settings with Clang or GCC:
cannam@133 417
cannam@133 418 * `-Wall -Wextra`: Enable most warnings.
cannam@133 419 * `-Wglobal-constructors`: (Clang-only) This catches global variables with constructors, which KJ style disallows (see above). You will, however, want to disable this warning in tests, since test frameworks use global constructors and are excepted from the style rule.
cannam@133 420 * `-Wno-sign-compare`: While comparison between signed and unsigned values could be a serious bug, we find that in practice this warning is almost always spurious.
cannam@133 421 * `-Wno-unused-parameter`: This warning is always spurious. I have never seen it find a real bug. Worse, it encourages people to delete parameter names which harms readability.
cannam@133 422
cannam@133 423 For development builds, `-Werror` should also be enabled. However, this should not be on by default in open source code as not everyone uses the same compiler or compiler version and different compiler versions often produce different warnings.
cannam@133 424
cannam@133 425 ### Tools
cannam@133 426
cannam@133 427 We use:
cannam@133 428
cannam@133 429 * Clang for compiling.
cannam@133 430 * `KJ_DBG()` for simple debugging.
cannam@133 431 * Valgrind for complicated debugging.
cannam@133 432 * [Ekam](https://github.com/sandstorm-io/ekam) for a build system.
cannam@133 433 * Git for version control.
cannam@133 434
cannam@133 435 ## Irrelevant formatting rules
cannam@133 436
cannam@133 437 Many style guides dwell on formatting. We mention it only because it's vaguely nice to have some formatting consistency, but know that this section is the *least* relevant section of the document.
cannam@133 438
cannam@133 439 As a code reviewer, when you see a violation of formatting rules, think carefully about whether or not it really matters that you point it out. If you believe the author may be unfamiliar with the rules, it may be worth letting them know to read this document, if only so that they can try to be consistent in the future. However, it is NOT worth the time to comment on every misplaced whitespace. As long as the code is readable, move on.
cannam@133 440
cannam@133 441 ### Naming
cannam@133 442
cannam@133 443 * Type names: `TitleCase`
cannam@133 444 * Variable, member, function, and method names: `camelCase`
cannam@133 445 * Constant and enumerant names: `CAPITAL_WITH_UNDERSCORES`
cannam@133 446 * Macro names: `CAPITAL_WITH_UNDERSCORES`, with an appropriate project-specific prefix like `KJ_` or `CAPNP_`.
cannam@133 447 * Namespaces: `oneword`. Namespaces should be kept short, because you'll have to type them a lot. The name of KJ itself was chosen for the sole purpose of making the namespace easy to type (while still being sufficiently unique). Use a nested namespace called `_` to contain package-private declarations.
cannam@133 448 * Files: `module-name.c++`, `module-name.h`, `module-name-test.c++`
cannam@133 449
cannam@133 450 **Rationale:** There has never been broad agreement on C++ naming style. The closest we have is the C++ standard library. Unfortunately, the C++ standard library made the awful decision of naming types and values in the same style, losing a highly useful visual cue that makes programming more pleasant, and preventing variables from being named after their type (which in many contexts is perfectly appropriate).
cannam@133 451
cannam@133 452 Meanwhile, the Java style, which KJ emulates, has been broadly adopted to varying degrees in other languages, from Javascript to Haskell. Using a similar style in KJ code makes it less jarring to switch between C++ and those other languages. Being consistent with Javascript is especially useful because it is the one language that everyone pretty much has to use, due to its use in the web platform.
cannam@133 453
cannam@133 454 There has also never been any agreement on C++ file extensions, for some reason. The extension `.c++`, though not widely used, is accepted by all reasonable tools and is clearly the most precise choice.
cannam@133 455
cannam@133 456 ### Spacing and bracing
cannam@133 457
cannam@133 458 * Indents are two spaces.
cannam@133 459 * Never use tabs.
cannam@133 460 * Maximum line length is 100 characters.
cannam@133 461 * Indent a continuation line by four spaces, *or* line them up nicely with the previous line if it makes it easier to read.
cannam@133 462 * Place a space between a keyword and an open parenthesis, e.g.: `if (foo)`
cannam@133 463 * Do not place a space between a function name and an open parenthesis, e.g.: `foo(bar)`
cannam@133 464 * Place an opening brace at the end of the statement which initiates the block, not on its own line.
cannam@133 465 * Place a closing brace on a new line indented the same as the parent block. If there is post-brace code related to the block (e.g. `else` or `while`), place it on the same line as the closing brace.
cannam@133 466 * Always place braces around a block *unless* the block is so short that it can actually go on the same line as the introductory `if` or `while`, e.g.: `if (done) return;`.
cannam@133 467 * `case` statements are indented within the `switch`, and their following blocks are **further** indented (so the actual statements in a case are indented four spaces more than the `switch`).
cannam@133 468 * `public:`, `private:`, and `protected:` are reverse-indented by one stop.
cannam@133 469 * Statements inside a `namespace` are **not** indented unless the namespace is a short block that is just forward-declaring things at the top of a file.
cannam@133 470 * Set your editor to strip trailing whitespace on save, otherwise other people who use this setting will see spurious diffs when they edit a file after you.
cannam@133 471
cannam@133 472
cannam@133 473 if (foo) {
cannam@133 474 bar();
cannam@133 475 } else if (baz) {
cannam@133 476 qux(quux);
cannam@133 477 } else {
cannam@133 478 corge();
cannam@133 479 }
cannam@133 480
cannam@133 481 if (done) return;
cannam@133 482
cannam@133 483 switch (grault) {
cannam@133 484 case GARPLY:
cannam@133 485 print("mew");
cannam@133 486 break;
cannam@133 487 case WALDO: { // note: needs braces due to variable
cannam@133 488 Location location = findWaldo();
cannam@133 489 print(location);
cannam@133 490 break;
cannam@133 491 }
cannam@133 492 }
cannam@133 493
cannam@133 494 <br>
cannam@133 495
cannam@133 496 namespace external {
cannam@133 497 class Forward;
cannam@133 498 class Declarations;
cannam@133 499 namespace nested {
cannam@133 500 class More;
cannam@133 501 }
cannam@133 502 }
cannam@133 503
cannam@133 504 namespace myproj {
cannam@133 505
cannam@133 506 class Fred {
cannam@133 507 public:
cannam@133 508 Fred();
cannam@133 509 ~Fred();
cannam@133 510 private:
cannam@133 511 int plugh;
cannam@133 512 };
cannam@133 513
cannam@133 514 } // namespace myproj
cannam@133 515
cannam@133 516 **Rationale:** Code which is inconsistently or sloppily formatted gives the impression that the author is not observant or simply doesn't care about quality, and annoys other people trying to read your code.
cannam@133 517
cannam@133 518 Other than that, there is absolutely no good reason to space things one way or another.
cannam@133 519
cannam@133 520 ### Comments
cannam@133 521
cannam@133 522 * Always use line comments (`//`). Never use block comments (`/**/`).
cannam@133 523
cannam@133 524 **Rationale:** Block comments don't nest. Block comments tend to be harder to re-arrange, whereas a group of line comments can be moved easily. Also, typing `*` is just way harder than typing `/` so why would you want to?
cannam@133 525
cannam@133 526 * Write comments that add useful information that the reader might not already know. Do NOT write comments which say things that are already blatantly obvious from the code. For example, for a function `void frob(Bar bar)`, do not write a comment `// Frobs the Bar.`; that's already obvious. It's better to have no comment.
cannam@133 527
cannam@133 528 * Doc comments go **after** the declaration. If the declaration starts a block, the doc comment should go inside the block at the top. A group of related declarations can have a single group doc comment after the last one as long as there are no black lines between the declarations.
cannam@133 529
cannam@133 530 int foo();
cannam@133 531 // This is documentation for foo().
cannam@133 532
cannam@133 533 class Bar {
cannam@133 534 // This is documentation for Bar.
cannam@133 535 public:
cannam@133 536 Bar();
cannam@133 537
cannam@133 538 inline int baz() { return 5; }
cannam@133 539 inline int qux() { return 6; }
cannam@133 540 // This is documentation for baz() and qux().
cannam@133 541 };
cannam@133 542
cannam@133 543 **Rationale:** When you start reading a doc comment, the first thing you want to know is *what the heck is being documented*. Having to scroll down through a long comment to see the declaration, then back up to read the docs, is bad. Sometimes, people actually repeat the declaration at the top of the comment just so that it's visible. This is silly. Let's just put the comment after the declaration.
cannam@133 544
cannam@133 545 * TODO comments are of the form `// TODO(type): description`, where `type` is one of:
cannam@133 546 * `now`: Do before next `git push`.
cannam@133 547 * `soon`: Do before next stable release.
cannam@133 548 * `someday`: A feature that might be nice to have some day, but no urgency.
cannam@133 549 * `perf`: Possible performance enhancement.
cannam@133 550 * `security`: Possible security concern. (Used for low-priority issues. Obviously, code with serious security problems should never be written in the first place.)
cannam@133 551 * `cleanup`: An improvement to maintainability with no user-visible effects.
cannam@133 552 * `port`: Things to do when porting to a new platform.
cannam@133 553 * `test`: Something that needs better testing.
cannam@133 554 * `msvc`: Something to revisit when the next, hopefully less-broken version of Microsoft Visual Studio becomes available.
cannam@133 555 * others: Additional TODO types may be defined for use in certain contexts.
cannam@133 556
cannam@133 557 **Rationale:** Google's guide suggests that TODOs should bear the name of their author ("the person to ask for more information about the comment"), but in practice there's no particular reason why knowing the author is more useful for TODOs than for any other comment (or, indeed, code), and anyway that's what `git blame` is for. Meanwhile, having TODOs classified by type allows for useful searches, so that e.g. release scripts can error out if release-blocking TODOs are present.
cannam@133 558
cannam@133 559 ### File templates
cannam@133 560
cannam@133 561 Generally, a "module" should consist of three files: `module.h`, `module.c++`, and `module-test.c++`. One or more of these can be omitted if it would otherwise be empty. Use the following templates when creating new files.
cannam@133 562
cannam@133 563 Headers:
cannam@133 564
cannam@133 565 // Project Name - Project brief description
cannam@133 566 // Copyright (c) 2015 Primary Author and contributors
cannam@133 567 //
cannam@133 568 // Licensed under the Whatever License blah blah no warranties.
cannam@133 569
cannam@133 570 #ifndef HEADER_PATH_FILENAME_H_
cannam@133 571 #define HEADER_PATH_FILENAME_H_
cannam@133 572 // Documentation for file.
cannam@133 573
cannam@133 574 #include <kj/common.h>
cannam@133 575
cannam@133 576 namespace myproject {
cannam@133 577
cannam@133 578 // declarations
cannam@133 579
cannam@133 580 namespace _ { // private
cannam@133 581
cannam@133 582 // private declarations
cannam@133 583
cannam@133 584 } // namespace _ (private)
cannam@133 585
cannam@133 586 } // namespace myproject
cannam@133 587
cannam@133 588 #endif // HEADER_PATH_FILENAME_H_
cannam@133 589
cannam@133 590 Source code:
cannam@133 591
cannam@133 592 // Project Name - Project brief description
cannam@133 593 // Copyright (c) 2015 Primary Author and contributors
cannam@133 594 //
cannam@133 595 // Licensed under the Whatever License blah blah no warranties.
cannam@133 596
cannam@133 597 #include "this-module.h"
cannam@133 598 #include <other-module.h>
cannam@133 599
cannam@133 600 namespace myproject {
cannam@133 601
cannam@133 602 // definitions
cannam@133 603
cannam@133 604 } // namespace myproject
cannam@133 605
cannam@133 606 Test:
cannam@133 607
cannam@133 608 // Project Name - Project brief description
cannam@133 609 // Copyright (c) 2015 Primary Author and contributors
cannam@133 610 //
cannam@133 611 // Licensed under the Whatever License blah blah no warranties.
cannam@133 612
cannam@133 613 #include "this-module.h"
cannam@133 614 #include <other-module.h>
cannam@133 615
cannam@133 616 namespace myproject {
cannam@133 617 namespace {
cannam@133 618
cannam@133 619 // KJ_TESTs
cannam@133 620
cannam@133 621 } // namespace
cannam@133 622 } // namespace myproject
cannam@133 623
cannam@133 624 Note that in both the source and test files, you should *always* include the corresponding header first, in order to ensure that it is self-contained (does not secretly require including some other header before it).