... | ... | @@ -133,6 +133,8 @@ Other, non-Haskell-code is indented with a mixture of tabs and spaces, and is st |
|
|
|
|
|
One of the most serious difficulties in a large, long-lived project is keeping technical documentation up to date. We have no silver bullet, but we offer one low-tech mechanism that has served us particularly well: **Notes**.
|
|
|
|
|
|
### 2.1 Notes: the basic idea
|
|
|
|
|
|
When writing code, there is often a moment when a careful programmer will mentally say something like "This data type has an important invariant". She is faced with two choices, both unsatisfactory. She can add the invariant as a comment, but that can make the data type declaration too long, so that it is hard to see what the constructors are. Alternatively, she can document the invariant elsewhere, and risk it going out of date. Over twenty years, everything goes out of date!
|
|
|
|
|
|
Thus motivated, we use the following very simple convention:
|
... | ... | @@ -148,7 +150,8 @@ Thus motivated, we use the following very simple convention: |
|
|
FunTy (TyConApp (~) [a, [b]]) $
|
|
|
blah
|
|
|
```
|
|
|
At the point where the comment is relevant, we add a short comment referring to the Note:
|
|
|
|
|
|
* At the point where the comment is relevant, we add a short comment referring to the Note:
|
|
|
```
|
|
|
data Type
|
|
|
= FunTy Type Type -- See Note [Equality-constrained types]
|
... | ... | @@ -157,11 +160,45 @@ Thus motivated, we use the following very simple convention: |
|
|
```
|
|
|
The comment highlights that something interesting is going on, and gives a precise reference to the comment that explains. It sounds trivial, but the precision is vastly better than our previous habit of saying "see the comment above", because it often was not clear which of the many comments above was intended, and after a few years the comment was not even above (it was below, or gone altogether).
|
|
|
|
|
|
* Notes should be copiously illustrated with concrete examples, and should point specifically to tickets that give relevant background detail. The extra space afforted by a Note (rather than an inline comment) makes it easy to to give such examples without breaking up the code it describes.
|
|
|
|
|
|
Not only is it possible to go from the code that refers to the Note to the Note itself, but the reverse is also possible, and that is often useful. Moreover, the same Note may be referred to from multiple points in the code.
|
|
|
|
|
|
This simple, ASCII-only technique, with no automated support, has transformed our lives: GHC's source code has thousands of Notes, and the number grows daily.
|
|
|
We have a lint check in CI to identify references to Notes that don't exist.
|
|
|
|
|
|
### 2.2 Overview Notes
|
|
|
|
|
|
Suppose you wonder "how is `unsafeCoerce` implemented in GHC?", or "how are
|
|
|
floating-point literals represented at compile time?" or "what does it mean
|
|
|
to say that two types are equal in GHC?". There is often no one bit of code that will answer such questions. *But there can be one Note!"
|
|
|
|
|
|
We strongly encourage **overview Notes** that summarise how the compiler deals with a particular topic.
|
|
|
|
|
|
An overview Note should
|
|
|
|
|
|
* **Topic**. Identify its topic/problem.
|
|
|
|
|
|
* **Design**. Explain the overall design -- give the big picture.
|
|
|
|
|
|
* **Moving parts**. Point to the "moving parts"; that is, the key bits of code that implement
|
|
|
the feature. These pointers should be quite specific, referring to
|
|
|
functions and data types by name. (Those functions and data types should
|
|
|
in turn refer back to the overview Note.)
|
|
|
|
|
|
* **Wrinkles**. List "wrinkles"; that is, any non-obvious corners that need special treatment.
|
|
|
This overlaps with the previous bullet a bit; again we would typically point
|
|
|
to the specific code that deals with the non-obvious corner.
|
|
|
|
|
|
It is often helpful to give a name to each wrinkle, such as (W7); then you can say (elsewhere) `-- See wrinkle (W7) of Note [Wombat]`. Precision is so helpufl!
|
|
|
|
|
|
A good example is `Note [Implementing unsafeCoerce]` in the library `base:Unsafe.Coerce`.
|
|
|
Another is `Note [Quasi-quote overview]` in `Language.Haskell.Syntax.Expr`.
|
|
|
|
|
|
Many (not all) MRs would be strengthened by adding a suitable overview Note, that
|
|
|
summarises the overall design. An overview makes the MR much easier to review.
|
|
|
|
|
|
|
|
|
## 3. Tickets, merge requests, and commits
|
|
|
|
|
|
### 3.1 Every MR should have a ticket
|
... | ... | |