Context Navigation

Coding Conventions

The golden rule is to follow whatever conventions are already being used in the module you're editing. If you're creating a new module then follow the conventions used in existing modules.

If you're not sure what the conventions are, then ask. If you can think of a better way of doing it then let us know on the mailing list. This goes for development process and the use of library functions, as much as formatting and commenting style. The DDC project was started years ago, and times change...

Comments

Critital: If you tried to understand something but gave up before doing so, then open a ticket on the trac and set the ticket type to document. This is a bug against the maintainability of the software. Don't assume that the next person that looks at the same code will be able to make more sense of it than you could, or have more patience.

Each top-level definition should have a comment explaining what it is for. One liners are fine.

Running comments in the bodies of functions are encouraged. Write down what you were expecting the code to do when you wrote it, so it reads like a story. Aim for 1 comment line at least every 5-10 code lines, depending on how complex the code is. This level of commenting would be overkill for a cookie-cutter program like a database GUI, but compilers are a completely different beast. See the ​CheckExp module in the type checker for a good example.

All top-level bindings should have a type signature. Exceptions can be made for functions that are continuations of others, as they will never need to be called from outside the module they are defined in. If you have more than a few dividers in a module then consider breaking it up into smaller modules.

Such dividers increase the structure of the code and help the reader find things, especially with syntax highlighting editors. Most dividers should be 100, 80 or 40 chars wide.

Spacing

Tabs are 8 spaces. The reason being that when you cat a text file to a unix console they come out as 8 spaces. Keep your editor set to tabs-as-8-spaces or you'll end up committing misaligned code.

Corollary to the above: don't use tabs. Keep your editor set to 'soft-tabs' mode so that when you press the tab key it inserts 8 spaces.

Most code should fit in 80 columns, but it's ok to use up to 100 if needed. Don't go over 100 columns.

Layout

We try to avoid having multiple layout styles in DDC. Having different styles creates "accidental complexity", that is, syntactic differences in the source that don't equate to real functional differences. If we change layout style then this should be documented here, so that we can migrate the code base towards it.

If a function does several things in a regular way, then it should look like that in the source code. This means you should line up arguments to similar function calls. For example, use this:

Avoid using names like pastaSalad' and pastaSalad'', because the prime doesn't provide any additional documentation.

Name conversion functions like globOfTops :: [Top] -> Glob instead of topsToGlob :: [Top] -> Glob. The type may be the opposite way around compared to the name, but it makes the source code easier to read. Consider (globOfTops someTops) vs (topsToGlob someTops).

If part of a variable name reflects its type, then put that part out the front. For example, source code variables of type Shared.Var should be named something like vThing, with a v out the front. Sets or lists of variables should be named vsThing with vs out the front. Avoid using names like thingVar and thingVars. We're not mandating Hungarian Notation, but if you're going to name a variable after a type anyway, then put the type part out the front.

Structure

Keep the sizes of the modules small. If a module has more than about 400 lines then consider breaking it up. Modules with just 100 lines are fine. Using small modules makes them easier to digest, forces you to think about the overall structure of the code, and helps parallel builds.

Prefer let over where

Using a "where" is ok when baz does something trivial, like initialise a loop. However, any time "baz" does something interesting you should use a let, otherwise the conceptual flow of the code is ruined. Using let over where also makes it easier to convert to strict Disciple code.