A few words about what we’re striving for in our comments, particularly in Core. Every shop has their own commenting style, so I worry that if you find our comments strange or lacking in some way you may just think, “Gee, that’s a weird a way to comment your code, but I guess that’s how they like to do it.” Now you’ll know our intent, so please do point out where our execution differs.

You might also find this useful if you want to contribute to Core.

If you’re straight out of university, you might not have worked on large code bases with others enough to have even thought about these questions, and you might find this intersting on those grounds. For whatever reason, it’s one of those things you’re usually just expected to pick up on the job.

Anyway, here are our basic thoughts. They’re always evolving, and have until now mostly just been an oral tradition, but do reflect a rough consensus arrived at after a lot of thinking and experience.

  1. Readers usually want more high-level comments and fewer low-level comments than you think. A good example is that users love that one-sentence comment at the top of a module that makes the whole thing click in place. For example, if the top of Flat_array says “This is basically like a regular Array of tuples, except the tuples aren’t boxed. The slots in the tuple might be pointers but the tuples in the Array are inlined into the Array. This means that copying has to occur when you pull a tuple out of the Array, but not when you just pull a slot out of a tuple in the Array.” then the whole rest of the module is obvious, and will barely need comments.

  2. Avoid redundant comments, e.g.:

    (* [remove t elt] removes [elt] from [t]. *)
    (* [remove_top t] remove the top element from [t] *)
    (* [child pool t] return the child of [t] *)
    val child : 'a Pool.t -> 'a t -> 'a t

    Generally, try not to say things that are obvious. Imagine that an actual person asked you, “Hey, what’s this child function?” and dictate your answer into the comment. If your answer is just, “Ok, you didn’t read the comment at the top of the module, did you?” then skip it.

  3. Put comments for users of a module in the mli and comments for the changers of a module in the ml.

  4. When you make a feature (see this earlier post on feature-based review), make sure the comments are updated on any modules you changed. If you didn’t update the comment, it suggests you didn’t read it, which suggests you didn’t expect it to be useful. If in fact it isn’t, just remove it. An incorrect comment is worse than no comment.

  5. Give more external context and less internal details. The internal stuff is already in the code, while the external stuff would otherwise be left unspecified. For example, internally we have an Mpv for rounding prices to something exchanges will accept. (For example, the “minimum price variation” or “tick size” for most US stocks is one penny, but for low-priced stocks it can be smaller.) This module is where new hires will end up if they don’t yet know about this, so it’s a good place to explain how it works. It’s not so necessary to explain the details of the module itself – it’s pretty straight forward once you have the context.

  6. After you’ve written a good comment, reconsider the code and see if you can obviate the comment. A common pattern is that:

    (* x is a y *)
    val x : t

    can often be better written:

    val y : t

    If written in the second form you don’t feel like you have to explain that y is an x, then the code has been improved.

  7. As a general rule, a comment that required thought to create saves the reader more thought than a comment that was easy to generate.

  8. Often, it’s more important to say what’s bad about the code than what’s good. What are the caveats? When can it fail? What cases aren’t handled?

  9. Prevent obvious improvements that are actually disimprovements. For example, if something could be refactored to be clearer, shorter, and slower, add a (* performance hack *) comment. With just those two words, you clarify that the reader isn’t missing something, the code really is redundant, and also that it shouldn’t be “fixed” in the author’s opinion.

  10. Give the intuition, not the proof. Examples are often good – you could comment a fibonacci generator with (* 1, 1, 2, 3, 5, 8, 13, ... *). Or a link to Wikipedia. Too much (* For all n > 0, [f(n)] = [f( ... tends to be no better than just reading the code. If the comment and the code explain the same thing two ways, it adds more if they’re two very different ways.

  11. Don’t be too rigid in following these rules, or any other rules. Comments are for humans, and humans are complicated, so the best way to explain your ideas will depend on lots of things. Hard rules like “every function needs a comment” do more harm than good.