wiki:NewStyleGuidelines

This page will eventually hold the new style guidelines. For now, I'm putting in the link to Ryan's document on the new MLPACK.

 http://www.igglybob.com/mlpack_future.pdf

Below are various notes on how to format things. These will be assembled into a coherent page/document when they are done. If you think something here is inconsistent, come find me (Ryan) in person and we can talk about it and come to some kind of conclusion. These are rules we should code by for consistency in our library, but that does not mean that we cannot change the rules to be better.

Tabbing

Tabs should be two spaces wide. i.e.

void Class::Method(int num)
{
  DoSomething();

  for(int i = 0; i < num; i++)
    DoSomethingElse(i);
}

Use spaces, not tab characters. See  jwz's rant for more information and reasoning. If you're using vim, here is what should go in your .vimrc:

set softtabstop=2
set expandtab
set shiftwidth=2

One exception to this rule is the public: and private: keywords in classes, which should be indented just one space:

class X 
{ 
 public: 
  // Stuff. 
 
 private: 
  // Stuff. 
}; 

Line Length and Wrapping

Lines should be no more than 80 characters wide. This was chosen because it is a standard for other projects out there, and it is not too difficult to adhere to. Also, it makes putting code samples in a paper possible and easy.

When wrapping a line, the next line should be tabbed twice from where the previous line began. An example is easier to understand:

void Class::Method(arma::mat& xx, const arma::mat& y)
{
  // We assume local variables arma::vec z and m.

  xx = y * SomeReallyLongMethodName(z, m) + 
      SomeOtherReallyLongMethodNameThatIsLong(z, m) +
      AThirdReallyLongMethodNameThatIsAlsoVeryLong(z, m);
}

As a side note, try to avoid method names that are that long if possible.

Method Declarations

Suppose you have a method with parameters that ends up being longer than 80 characters. Wrap it such that each new line of parameters lines up with the previous line of parameters, like so:

AllNN::AllNN(arma::mat& references_in,
             struct datanode* module_in,
             bool alias_matrix,
             bool naive)

If the method names are so long that you can't make that fit, you can do this:

AllNN::AllNN(
    arma::mat& references_in,
    struct datanode* module_in,
    bool alias_matrix,
    bool naive)

And if the method and class names are too long for that, you could do this:

void AReallyLongClassName::
SomeReallySuperLongMethodNameWhichShouldBeShorter(
    arguments)

If you add templates too, you can do this:

void KMeans<
    DistanceMetric,
    InitialPartitionPolicy,
    EmptyClusterPolicy>::
Cluster(const arma::mat& data,
        const size_t clusters,
        arma::Col<size_t>& assignments)

Constructor Initialization Lists

We have already defined how parameters should be, but initialization lists should adhere to the line wrapping style with two tabs. The same example is below:

AllNN::AllNN(arma::mat& references_in, struct datanode* module_in,
             bool alias_matrix, bool naive) :
    module_(module_in),
    naive_(naive),
    references_(references_in.memptr(), references_in.n_rows,
        references_in.n_cols, !alias_matrix),
    queries_(references.memptr(), references.n_rows, references.n_cols,
        false)
{
  // Do some stuff inside of the constructor here that could not be done with
  // initialization lists.
}

Again, it may be easier to read each initialization list entry on separate lines if many things are being initialized. That is left up to the developer to decide.

Note that on very long initialization list lines, the wrapping rules are again used.

Brace Placement

Avoid placing opening braces on the same line as a loop/if/else/switch/function/class. The block is more readable with braces aligned.

Use

if (n > 12)
{
  x += 2;
  y -= 12.5;
}

rather than

if (n > 12) {
  x += 2;
  y -= 12.5;
}

To conserve lines, refrain from using braces if the if, while, or for statement applies to a single statement.

Namespaces

The exception to the rules of braces and tabbing is namespaces. For simplicity, write this:

namespace mlpack { 
namespace mvu { 
	 
// stuff goes here 
 	 
}; // namespace mvu 
}; // namespace mlpack 

Don't indent anything inside namespaces -- it's a waste of columns, especially when you are several namespaces deep.

Operator and Keyword Spacing Rules

Use spaces between your operators for readability. Below is an example:

for (int i = 0; i < 10; i++)
{
  if (i > 5)
    someValue = (4 * i) + 5;
  else
    someValue = (someBool ? (3 * i) : 2);
}

Things like i=(4+5-i) are not cool, and are not easy to read. A space between parentheses and what is inside of them, like i = ( 4 + 5 - i ) is technically superfluous but is still readable so is not a huge problem. Also do note the spaces between the for and if operators and the opening parentheses.

Naming Conventions

Use  camel casing for all names. Capitalize class and method names. Variable, reference, and pointer names begin with a lower case letter. Setters and getters share names with their respective data members, distinguished by the case of the first letter of each of their names.

class Hilarious
{
  private:
    int aLaugh;
    char aChuckle;
    matrix& matr;
  public:
    Hilarious();
    const int ALaugh() { return aLaugh; }
    void ALaugh(int i) { aLaugh = i; }
    const matrix& Matr() { return matr; }
}

The convention, for now, is to pass an argument in the setter to permit data consistency checks before assigning the value.

Casting

When doing a C-style cast, use spaces:

double d = (double) integer;

and not

double d = (double)integer;