annotate src/capnproto-0.6.0/style-guide.md @ 169:223a55898ab9 tip default

Add null config files
author Chris Cannam <cannam@all-day-breakfast.com>
date Mon, 02 Mar 2020 14:03:47 +0000
parents 45360b968bf4
children
rev   line source
cannam@147 1 # KJ Style
cannam@147 2
cannam@147 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@147 4
cannam@147 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@147 6
cannam@147 7 **Table of Contents**
cannam@147 8
cannam@147 9 - [Rule #1: There are no rules](#rule-1-there-are-no-rules)
cannam@147 10 - [Design Philosophy](#design-philosophy)
cannam@147 11 - [Value Types vs. Resource Types](#value-types-vs-resource-types)
cannam@147 12 - [RAII (Resource Acquisition Is Initialization)](#raii-resource-acquisition-is-initialization)
cannam@147 13 - [Ownership](#ownership)
cannam@147 14 - [No Singletons](#no-singletons)
cannam@147 15 - [Exceptions](#exceptions)
cannam@147 16 - [Threads vs. Event Loops](#threads-vs-event-loops)
cannam@147 17 - [Lazy input validation](#lazy-input-validation)
cannam@147 18 - [Premature optimization fallacy](#premature-optimization-fallacy)
cannam@147 19 - [Text is always UTF-8](#text-is-always-utf-8)
cannam@147 20 - [C++ usage](#c-usage)
cannam@147 21 - [Use C++11 (or later)](#use-c11-or-later)
cannam@147 22 - [Heap allocation](#heap-allocation)
cannam@147 23 - [Pointers, references](#pointers-references)
cannam@147 24 - [Constness](#constness)
cannam@147 25 - [Inheritance](#inheritance)
cannam@147 26 - [Exceptions Usage](#exceptions-usage)
cannam@147 27 - [Template Metaprogramming](#template-metaprogramming)
cannam@147 28 - [Global Constructors](#global-constructors)
cannam@147 29 - [`dynamic_cast`](#dynamic_cast)
cannam@147 30 - [Use of Standard libraries](#use-of-standard-libraries)
cannam@147 31 - [Compiler warnings](#compiler-warnings)
cannam@147 32 - [Tools](#tools)
cannam@147 33 - [Irrelevant formatting rules](#irrelevant-formatting-rules)
cannam@147 34 - [Naming](#naming)
cannam@147 35 - [Spacing and bracing](#spacing-and-bracing)
cannam@147 36 - [Comments](#comments)
cannam@147 37 - [File templates](#file-templates)
cannam@147 38
cannam@147 39 ## Rule #1: There are no rules
cannam@147 40
cannam@147 41 This guide contains suggestions, not rules.
cannam@147 42
cannam@147 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@147 44
cannam@147 45 ## Design Philosophy
cannam@147 46
cannam@147 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@147 48
cannam@147 49 ### Value Types vs. Resource Types
cannam@147 50
cannam@147 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@147 52
cannam@147 53 * Value types make sense to copy (though they don't necessarily have copy constructors). Resource types are not copyable.
cannam@147 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@147 55 * Value types almost always have implicit destructors. Resource types may have an explicit destructor.
cannam@147 56 * Value types should only be compared by value, not identity. Resource types can only be compared by identity.
cannam@147 57 * Value types make sense to serialize. Resource types fundamentally cannot be serialized.
cannam@147 58 * Value types rarely use inheritance and never have virtual methods. Resource types commonly do.
cannam@147 59 * Value types generally use templates for polymorphism. Resource types generally use virtual methods / abstract interfaces.
cannam@147 60 * You might even say that value types are used in functional programming style while resource types are used in object-oriented style.
cannam@147 61
cannam@147 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@147 63
cannam@147 64 ### RAII (Resource Acquisition Is Initialization)
cannam@147 65
cannam@147 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@147 67
cannam@147 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@147 69
cannam@147 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@147 71
cannam@147 72 ### Ownership
cannam@147 73
cannam@147 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@147 75
cannam@147 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@147 77
cannam@147 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@147 79
cannam@147 80 An object can never own itself, including transitively.
cannam@147 81
cannam@147 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@147 83
cannam@147 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@147 85
cannam@147 86 * A pointer or reference passed as a constructor parameter must remain valid for the lifetime of the constructed object.
cannam@147 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@147 88 * A pointer or reference returned by a method remains valid at least until the object whose method was called is destroyed.
cannam@147 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@147 90
cannam@147 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@147 92
cannam@147 93 #### Reference Counting
cannam@147 94
cannam@147 95 Reference counting is allowed, in which case an object will have multiple owners.
cannam@147 96
cannam@147 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@147 98
cannam@147 99 * Reference-counted value types should be immutable.
cannam@147 100 * Reference-counted resource types should have an interface which clearly specifies how multiple clients should coordinate.
cannam@147 101
cannam@147 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@147 103
cannam@147 104 Avoid reference counting when it is not absolutely necessary.
cannam@147 105
cannam@147 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@147 107
cannam@147 108 ### No Singletons
cannam@147 109
cannam@147 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@147 111
cannam@147 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@147 113
cannam@147 114 See ["Singletons Considered Harmful"](http://www.object-oriented-security.org/lets-argue/singletons) for a complete discussion.
cannam@147 115
cannam@147 116 #### Global registries are singletons
cannam@147 117
cannam@147 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@147 119
cannam@147 120 // BAD BAD BAD
cannam@147 121 REGISTER_PLUGIN("foo", fooEntryPoint);
cannam@147 122
cannam@147 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@147 124
cannam@147 125 #### What to do instead
cannam@147 126
cannam@147 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@147 128
cannam@147 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@147 130
cannam@147 131 #### Working around OS singletons
cannam@147 132
cannam@147 133 Unfortunately, operating system APIs are traditionally singleton-heavy. The most obvious example is, of course, the filesystem.
cannam@147 134
cannam@147 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@147 136
cannam@147 137 ### Exceptions
cannam@147 138
cannam@147 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@147 140
cannam@147 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@147 142
cannam@147 143 For example, exceptions may indicate conditions like:
cannam@147 144
cannam@147 145 * Logistics of software development:
cannam@147 146 * There is a bug in the code.
cannam@147 147 * The requested method is not implemented.
cannam@147 148 * Logistics of software usage:
cannam@147 149 * There is an error in the program's configuration.
cannam@147 150 * The input is invalid.
cannam@147 151 * Logistics of distributed systems:
cannam@147 152 * A network connection was reset.
cannam@147 153 * An optimistic transaction was aborted due to concurrent modification.
cannam@147 154 * Logistics of physical computation:
cannam@147 155 * The system's resources are exhausted (e.g. out of memory, out of disk space).
cannam@147 156 * The system is overloaded and must reject some requests to avoid long queues.
cannam@147 157
cannam@147 158 #### Business logic should never catch
cannam@147 159
cannam@147 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@147 161
cannam@147 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@147 163
cannam@147 164 #### How to handle an exception
cannam@147 165
cannam@147 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@147 167
cannam@147 168 * On network disconnect or transaction failures, back up and start over from the beginning (restore connections and state, redo operations).
cannam@147 169 * On resources exhausted / overloaded, retry again later, with exponential back-off.
cannam@147 170 * On unimplemented methods, retry with a different implementation strategy, if there is one.
cannam@147 171 * When no better option is available, report the problem to a human (the user and/or the developer).
cannam@147 172
cannam@147 173 #### Exceptions can happen anywhere (including destructors)
cannam@147 174
cannam@147 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@147 176
cannam@147 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@147 178
cannam@147 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@147 180
cannam@147 181 Alas, C++ is what it is. So, in KJ, we work around the problem in a couple ways:
cannam@147 182
cannam@147 183 * `kj::UnwindDetector` may be used to detect when a destructor is called during unwind and squelch secondary exceptions.
cannam@147 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@147 185
cannam@147 186 #### Allowing `-fno-exceptions`
cannam@147 187
cannam@147 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@147 189
cannam@147 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@147 191
cannam@147 192 ### Threads vs. Event Loops
cannam@147 193
cannam@147 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@147 195
cannam@147 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@147 197
cannam@147 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@147 199
cannam@147 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@147 201
cannam@147 202 ### Lazy input validation
cannam@147 203
cannam@147 204 As we all know, you should always validate your input.
cannam@147 205
cannam@147 206 But, when should you validate it? There are two plausible answers:
cannam@147 207
cannam@147 208 * Upfront, on receipt.
cannam@147 209 * Lazily, on use.
cannam@147 210
cannam@147 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@147 212
cannam@147 213 However, upfront validation has some big problems.
cannam@147 214
cannam@147 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@147 216
cannam@147 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@147 218
cannam@147 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@147 220
cannam@147 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@147 222
cannam@147 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@147 224
cannam@147 225 ### Premature optimization fallacy
cannam@147 226
cannam@147 227 _"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil."_ -- Donald Knuth
cannam@147 228
cannam@147 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@147 230
cannam@147 231 (Credit: [Stop Misquoting Donald Knuth!](http://www.joshbarczak.com/blog/?p=580))
cannam@147 232
cannam@147 233 You should not obsess over optimization or write unmaintainable code for the sake of speed.
cannam@147 234
cannam@147 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@147 236
cannam@147 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@147 238
cannam@147 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@147 240
cannam@147 241 ### Text is always UTF-8
cannam@147 242
cannam@147 243 Always encode text as UTF-8. Always assume text is encoded as UTF-8.
cannam@147 244
cannam@147 245 (Do not, however, assume text is _valid_ UTF-8; see the section on lazy validation.)
cannam@147 246
cannam@147 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@147 248
cannam@147 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@147 250
cannam@147 251 ## C++ usage
cannam@147 252
cannam@147 253 This section contains guidelines for usage of C++ language features.
cannam@147 254
cannam@147 255 ### Use C++11 (or later)
cannam@147 256
cannam@147 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@147 258
cannam@147 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@147 260
cannam@147 261 ### Heap allocation
cannam@147 262
cannam@147 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@147 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@147 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@147 266
cannam@147 267 ### Pointers, references
cannam@147 268
cannam@147 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@147 270 * Always use `kj::ArrayPtr<T>` rather than `T*` to point to an array.
cannam@147 271 * Always use `kj::StringPtr` rather than `const char*` to point to a NUL-terminated string.
cannam@147 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@147 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@147 274
cannam@147 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@147 276
cannam@147 277 ### Constness
cannam@147 278
cannam@147 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@147 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@147 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@147 282
cannam@147 283 ### Inheritance
cannam@147 284
cannam@147 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@147 286
cannam@147 287 Interfaces should NOT declare a destructor, because:
cannam@147 288
cannam@147 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@147 290 * Declaring destructors for interfaces is tedious.
cannam@147 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@147 292
cannam@147 293 Multiple inheritance is allowed and encouraged, keeping in mind that you are usually inheriting interfaces.
cannam@147 294
cannam@147 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@147 296
cannam@147 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@147 298
cannam@147 299 ### Exceptions Usage
cannam@147 300
cannam@147 301 KJ's exception philosophy is described earlier in this document. Here we describe only how to actually use exceptions in code.
cannam@147 302
cannam@147 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@147 304
cannam@147 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@147 306
cannam@147 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@147 308
cannam@147 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@147 310
cannam@147 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@147 312
cannam@147 313 ### Template Metaprogramming
cannam@147 314
cannam@147 315 #### Reducing Verbosity
cannam@147 316
cannam@147 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@147 318
cannam@147 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@147 320
cannam@147 321 1. Define the struct as before, but with the name `Foo_<T>`.
cannam@147 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@147 323
cannam@147 324 Example:
cannam@147 325
cannam@147 326 template <typename T> struct IsConst_ { static constexpr bool value = false; };
cannam@147 327 template <typename T> struct IsConst_<const T> { static constexpr bool value = true; };
cannam@147 328 template <typename T> constexpr bool isConst() { return IsConst_<T>::value; }
cannam@147 329 // Return true if T is const.
cannam@147 330
cannam@147 331 Or:
cannam@147 332
cannam@147 333 template <typename T> struct UnConst_ { typedef T Type; };
cannam@147 334 template <typename T> struct UnConst_<const T> { typedef T Type; };
cannam@147 335 template <typename T> using UnConst = typename UnConst_<T>::Type;
cannam@147 336 // If T is const, return the underlying non-const type.
cannam@147 337 // Otherwise, just return T.
cannam@147 338
cannam@147 339 Now people can use your template metafunction without the pesky `::Type` or `::value` suffix.
cannam@147 340
cannam@147 341 #### Other hints
cannam@147 342
cannam@147 343 * To explicitly disable a template under certain circumstances, bind an unnamed template parameter to `kj::EnableIf`:
cannam@147 344
cannam@147 345 template <typename T, typename = kj::EnableIf(!isConst<T>())>
cannam@147 346 void mutate(T& ptr);
cannam@147 347 // T must not be const.
cannam@147 348
cannam@147 349 * Say you're writing a template type with a constructor function like so:
cannam@147 350
cannam@147 351 template <typename T>
cannam@147 352 Wrapper<T> makeWrapper(T&& inner);
cannam@147 353 // Wraps `inner` and returns the wrapper.
cannam@147 354
cannam@147 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@147 356
cannam@147 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@147 358
cannam@147 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@147 360
cannam@147 361 ### Global Constructors
cannam@147 362
cannam@147 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@147 364
cannam@147 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@147 366
cannam@147 367 Use Clang's `-Wglobal-constructors` warning to catch mistakes.
cannam@147 368
cannam@147 369 ### `dynamic_cast`
cannam@147 370
cannam@147 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@147 372
cannam@147 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@147 374
cannam@147 375 #### `-fno-rtti`
cannam@147 376
cannam@147 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@147 378
cannam@147 379 We do NOT recommend disabling RTTI in your own code.
cannam@147 380
cannam@147 381 ### Lambdas
cannam@147 382
cannam@147 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@147 384
cannam@147 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@147 386
cannam@147 387 ### Use of Standard libraries
cannam@147 388
cannam@147 389 #### C++ Standard Library
cannam@147 390
cannam@147 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@147 392
cannam@147 393 For these reasons and others, KJ aims to be a replacement for the C++ standard libraries.
cannam@147 394
cannam@147 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@147 396
cannam@147 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@147 398
cannam@147 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@147 400
cannam@147 401 * `kj/common.h`
cannam@147 402 * `kj/memory.h`
cannam@147 403 * `kj/array.h`
cannam@147 404 * `kj/string.h`
cannam@147 405 * `kj/vector.h`
cannam@147 406 * `kj/debug.h`
cannam@147 407
cannam@147 408 #### C Library
cannam@147 409
cannam@147 410 As a general rule of thumb, C library functions documented in man section 3 should be treated with skepticism.
cannam@147 411
cannam@147 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@147 413
cannam@147 414 ### Compiler warnings
cannam@147 415
cannam@147 416 Use the following warning settings with Clang or GCC:
cannam@147 417
cannam@147 418 * `-Wall -Wextra`: Enable most warnings.
cannam@147 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@147 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@147 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@147 422
cannam@147 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@147 424
cannam@147 425 ### Tools
cannam@147 426
cannam@147 427 We use:
cannam@147 428
cannam@147 429 * Clang for compiling.
cannam@147 430 * `KJ_DBG()` for simple debugging.
cannam@147 431 * Valgrind for complicated debugging.
cannam@147 432 * [Ekam](https://github.com/sandstorm-io/ekam) for a build system.
cannam@147 433 * Git for version control.
cannam@147 434
cannam@147 435 ## Irrelevant formatting rules
cannam@147 436
cannam@147 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@147 438
cannam@147 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@147 440
cannam@147 441 ### Naming
cannam@147 442
cannam@147 443 * Type names: `TitleCase`
cannam@147 444 * Variable, member, function, and method names: `camelCase`
cannam@147 445 * Constant and enumerant names: `CAPITAL_WITH_UNDERSCORES`
cannam@147 446 * Macro names: `CAPITAL_WITH_UNDERSCORES`, with an appropriate project-specific prefix like `KJ_` or `CAPNP_`.
cannam@147 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@147 448 * Files: `module-name.c++`, `module-name.h`, `module-name-test.c++`
cannam@147 449
cannam@147 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@147 451
cannam@147 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@147 453
cannam@147 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@147 455
cannam@147 456 ### Spacing and bracing
cannam@147 457
cannam@147 458 * Indents are two spaces.
cannam@147 459 * Never use tabs.
cannam@147 460 * Maximum line length is 100 characters.
cannam@147 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@147 462 * Place a space between a keyword and an open parenthesis, e.g.: `if (foo)`
cannam@147 463 * Do not place a space between a function name and an open parenthesis, e.g.: `foo(bar)`
cannam@147 464 * Place an opening brace at the end of the statement which initiates the block, not on its own line.
cannam@147 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@147 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@147 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@147 468 * `public:`, `private:`, and `protected:` are reverse-indented by one stop.
cannam@147 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@147 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@147 471
cannam@147 472
cannam@147 473 if (foo) {
cannam@147 474 bar();
cannam@147 475 } else if (baz) {
cannam@147 476 qux(quux);
cannam@147 477 } else {
cannam@147 478 corge();
cannam@147 479 }
cannam@147 480
cannam@147 481 if (done) return;
cannam@147 482
cannam@147 483 switch (grault) {
cannam@147 484 case GARPLY:
cannam@147 485 print("mew");
cannam@147 486 break;
cannam@147 487 case WALDO: { // note: needs braces due to variable
cannam@147 488 Location location = findWaldo();
cannam@147 489 print(location);
cannam@147 490 break;
cannam@147 491 }
cannam@147 492 }
cannam@147 493
cannam@147 494 <br>
cannam@147 495
cannam@147 496 namespace external {
cannam@147 497 class Forward;
cannam@147 498 class Declarations;
cannam@147 499 namespace nested {
cannam@147 500 class More;
cannam@147 501 }
cannam@147 502 }
cannam@147 503
cannam@147 504 namespace myproj {
cannam@147 505
cannam@147 506 class Fred {
cannam@147 507 public:
cannam@147 508 Fred();
cannam@147 509 ~Fred();
cannam@147 510 private:
cannam@147 511 int plugh;
cannam@147 512 };
cannam@147 513
cannam@147 514 } // namespace myproj
cannam@147 515
cannam@147 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@147 517
cannam@147 518 Other than that, there is absolutely no good reason to space things one way or another.
cannam@147 519
cannam@147 520 ### Comments
cannam@147 521
cannam@147 522 * Always use line comments (`//`). Never use block comments (`/**/`).
cannam@147 523
cannam@147 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@147 525
cannam@147 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@147 527
cannam@147 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@147 529
cannam@147 530 int foo();
cannam@147 531 // This is documentation for foo().
cannam@147 532
cannam@147 533 class Bar {
cannam@147 534 // This is documentation for Bar.
cannam@147 535 public:
cannam@147 536 Bar();
cannam@147 537
cannam@147 538 inline int baz() { return 5; }
cannam@147 539 inline int qux() { return 6; }
cannam@147 540 // This is documentation for baz() and qux().
cannam@147 541 };
cannam@147 542
cannam@147 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@147 544
cannam@147 545 * TODO comments are of the form `// TODO(type): description`, where `type` is one of:
cannam@147 546 * `now`: Do before next `git push`.
cannam@147 547 * `soon`: Do before next stable release.
cannam@147 548 * `someday`: A feature that might be nice to have some day, but no urgency.
cannam@147 549 * `perf`: Possible performance enhancement.
cannam@147 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@147 551 * `cleanup`: An improvement to maintainability with no user-visible effects.
cannam@147 552 * `port`: Things to do when porting to a new platform.
cannam@147 553 * `test`: Something that needs better testing.
cannam@147 554 * `msvc`: Something to revisit when the next, hopefully less-broken version of Microsoft Visual Studio becomes available.
cannam@147 555 * others: Additional TODO types may be defined for use in certain contexts.
cannam@147 556
cannam@147 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@147 558
cannam@147 559 ### File templates
cannam@147 560
cannam@147 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@147 562
cannam@147 563 Headers:
cannam@147 564
cannam@147 565 // Project Name - Project brief description
cannam@147 566 // Copyright (c) 2015 Primary Author and contributors
cannam@147 567 //
cannam@147 568 // Licensed under the Whatever License blah blah no warranties.
cannam@147 569
cannam@147 570 #ifndef HEADER_PATH_FILENAME_H_
cannam@147 571 #define HEADER_PATH_FILENAME_H_
cannam@147 572 // Documentation for file.
cannam@147 573
cannam@147 574 #include <kj/common.h>
cannam@147 575
cannam@147 576 namespace myproject {
cannam@147 577
cannam@147 578 // declarations
cannam@147 579
cannam@147 580 namespace _ { // private
cannam@147 581
cannam@147 582 // private declarations
cannam@147 583
cannam@147 584 } // namespace _ (private)
cannam@147 585
cannam@147 586 } // namespace myproject
cannam@147 587
cannam@147 588 #endif // HEADER_PATH_FILENAME_H_
cannam@147 589
cannam@147 590 Source code:
cannam@147 591
cannam@147 592 // Project Name - Project brief description
cannam@147 593 // Copyright (c) 2015 Primary Author and contributors
cannam@147 594 //
cannam@147 595 // Licensed under the Whatever License blah blah no warranties.
cannam@147 596
cannam@147 597 #include "this-module.h"
cannam@147 598 #include <other-module.h>
cannam@147 599
cannam@147 600 namespace myproject {
cannam@147 601
cannam@147 602 // definitions
cannam@147 603
cannam@147 604 } // namespace myproject
cannam@147 605
cannam@147 606 Test:
cannam@147 607
cannam@147 608 // Project Name - Project brief description
cannam@147 609 // Copyright (c) 2015 Primary Author and contributors
cannam@147 610 //
cannam@147 611 // Licensed under the Whatever License blah blah no warranties.
cannam@147 612
cannam@147 613 #include "this-module.h"
cannam@147 614 #include <other-module.h>
cannam@147 615
cannam@147 616 namespace myproject {
cannam@147 617 namespace {
cannam@147 618
cannam@147 619 // KJ_TESTs
cannam@147 620
cannam@147 621 } // namespace
cannam@147 622 } // namespace myproject
cannam@147 623
cannam@147 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).