drizzle
Profile
Search
 
Powered by SoftLayer
Coding Standards

Contents

Header Files

Keep #include directives to a minimum in header files. Prefer forward declaring classes/structs if at all possible.

Header File Dependencies

Don't use an #include when a forward declaration would suffice.

Names and Order of Includes

Every implementation file should start with:

#include <drizzled/server_includes.h>

All files, headers and implementation, should include everything they need to be self-sufficient. They should never assume something will be pre-included. config.h is the exception to this. All headers must assume this has been pre-included and must never include it directly.

If doing development on a file within the drizzle core i.e. in the drizzled directory, include directives should take the form:

#include "drizzled/server_includes.h"

If developing a plugin, then include directives should take the form:

#include <drizzled/server_includes.h>

Include Guards

All headers must use include guards.

For instance, if you are editing the file drizzled/plugin_authentication.h

You would use the following:

#ifndef DRIZZLED_PLUGIN_AUTHENICATION_H
#define DRIZZLED_PLUGIN_AUTHENICATION_H
 
#endif /* DRIZZLED_PLUGIN_AUTHENICATION_H */

Please always place a comment on the #endif.

Inline Functions

Define functions inline only when they are small (how small?).

It is important to know that functions are not always inlined even if they are declared as such; for example, virtual and recursive functions are not normally inlined. Usually recursive functions should not be inline. The main reason for making a virtual function inline is to place its definition in the class, either for convenience or to document its behavior, e.g., for accessors and mutators.

Scoping

Namespaces

using namespace should NEVER be used in header files.

For example, if you need to use std::string in a header, do this:

#include <string>
 
/* Prototype for foo() */
int foo(std::string arg);

use of std namespace

using namespace std; should ALWAYS be used in implementation files.

If you want to use the above function from foo.h, then do this:

#include <foo.h>
 
using namespace std;
 
string a= "test";
foo(a);

use of drizzled namespace

Within the drizzled/ directory in the core, as much code as possible that we write should be placed in the drizzled namespace. Always surround new classes with namespace drizzled { }.

NEVER place include statements inside of a namespace block.

Prefer the namespace drizzled { } over the using namespace drizzled; form in implementation files. If possible, all code after includes should be inside of a drizzled namespace block. Because of the old code, this is often not possible yet. In these cases, wrap what can be wrapped in a block, and either explicitly qualify other code for now, or also include a using namespace drizzled; directive.

Subsystems should get their own namespace matching the directory structure or subsystem. For instance, drizzled/plugin/authentication.h contains the class drizzled::plugin::Authentication.

other namespaces

Other namespaces may be used in implementation files by using a using namespace directive. NEVER using past the first level. For instance:

#include <google/protobuf/io.h>
 
using namespace google;
 
protobuf::io::CodedOutputStream foo;

plugins

Plugins are not members of the drizzled namespace. They should, therefore, not wrap themselves in drizzled namespace blocks. They should instead prefer to use the using namespace directives in their implementation files.

Nonmember, Static Member, and Global Functions

Sometimes it is useful, or even necessary, to define a function not bound to a class instance. Such a function can be either a static member or a nonmember function. Nonmember functions should not depend on external variables, and should nearly always exist in a namespace. Rather than creating classes only to group static member functions which do not share static data, use namespaces instead.

Functions defined in the same compilation unit as production classes may introduce unnecessary coupling and link-time dependencies when directly called from other compilation units; static member functions are particularly susceptible to this. Consider extracting a new class, or placing the functions in a namespace possibly in a separate library.

If you must define a nonmember function and it is only needed in its .cc file, use an unnamed namespace or static linkage to limit its scope.

Local Variables

Place a function's variables in the narrowest scope possible, and initialize variables in the declaration.

Global Variables

TODO: update this sub-section...

Types & Classes

Why? Long is not portable and in MySQL there are a number of places where we use it that I question if the code is really 64 bit clean.

Please use true/false with bools, not numbers (I really wish gcc would flag this). Also, when testing true and false be descriptive.

if (can_print == false) {...};

or

if (not can_print) {...}

Over

if (!(can_print)) {..};

Also, booleans should have a leading verb to make clear that it is boolean. Instead of "valid", use "is_valid". Instead of "drivers", use "has_drivers".

Doing Work in Constructors

Default Constructors

Copy Constructors

What is the standard on this? Do we expect all classes to have copy constructors?

Structs Vs. Classes

What is the standard on when to use a class versus a struct? Should we just always strive to use classes? I would say just always make something a class personally.

Operator Overloading

What is our standard on operator overloading?

Access Control

Make all data members private, and provide access to them through accessor functions as needed.

Declaration Order

Your class definition should start with its public: section, followed by its protected: section and then its private: section. If any of these sections are empty, omit them.

Exceptions will be made for cache alignment.

Write Short Functions

Long functions are sometimes appropriate, so no hard limit is placed on functions length. If a function exceeds about 40 lines, think about whether it can be broken up without harming the structure of the program.

Even if your long function works perfectly now, someone modifying it in a few months may add new behavior. This could result in bugs that are hard to find. Keeping your functions short and simple makes it easier for other people to read and modify your code.

You could find long and complicated functions when working with some code. Do not be intimidated by modifying existing code: if working with such a function proves to be difficult, you find that errors are hard to debug, or you want to use a piece of it in several different contexts, consider breaking up the function into smaller and more manageable pieces.

In summary, prefer functions that are small and focused.

Naming

General

Function names, variable names, and filenames should be descriptive; eschew abbreviation. Types and variables should be nouns, while functions should be "command" verbs.

Types

Structures should be named as "something_st". All structures which are use in a global context should by typedef'ed.

Name classes in caps style. Such as Table or TableShare.

Variables

Variable names are all lowercase, with underscores between words. For instance: my_exciting_local_variable.

Bools should be named "is_something" or "has_something".

Constants

Functions

Function names should use camel case and begin with a lower case verb explaining the action. "foo.setBar()" or "foo.replaceString()".

Namespaces

For classes in the drizzled/ directory, especially new ones, use the drizzled namespace. For classes in a subdirectory of drizzled, use an additional namespace.

Example:

For the base Replicator plugin class, in /drizzled/plugin/replicator.h:

namespace drizzled
{
namespace plugin
{
class Replicator
{
 ...
};
 
} /* end namespace drizzled::plugin */
} /* end namespace drizzled */

Enums

Enums should be used and should always have its members in all caps. The declaration type should be done in lower case.

Use enum instead of defines. Defines are for single shot "everything will be this". Enums create lists. If the values are going to go into a switch/case... they should be enums.

Comments

Comment Style

We will be using Doxygen to generate on-line source code documentation. Doxygen is very versatile and supports several different styles of commenting. In order to have some consistency in the code, below is the recommended commenting style.

Preceed Doxygen commands with the at-sign (@) instead of the backslash (\). E.g.:

@brief
@details

Use the Javadoc style of commenting for multi-line comment blocks. For example:

/**
 *  ...text...
 */

Note: The JAVADOC_AUTOBRIEF Doxygen option will be used.


File Comments

Documenting a source file is recommended, but is absolutely necessary if you want to document a global object (function, typedef, enum, macro, etc.). Otherwise, the documentation for the global object will not be generated.

A file should be commented at the beginning of the file.

Example:

/**
 * @file
 *   example.h
 *
 * @brief
 *   An example header file.
 *
 * @details
 *   A more detailed description here.
 */


Class Comments

All classes should be commented immediately preceeding the class definition in the header file.

Class Methods

The methods of the class should be commented within the header file, not the implementation file. The API of the class should be clearly exposed through the header file only. Describe what the method does, what its parameters are, and what it returns. If there are complex details about the implementation that you feel need documenting, do so inside the method in the implementation file.

Also see comments in the #Function and Method Comments section.

Class Member Variables

Member variables should be commented in the header, when appropriate. Members can be commented either above the variable declaration:

 /**
  * Brief description of myVar.
  * More detailed description of myVar that works because of JAVADOC_AUTOBRIEF.
  */
 int myVar;

Or, the member variables may be commented on the same line as the variable declaration:

  int myVar; ///< A brief description of myVar
 
  int myVar2; ///< This is a detailed description of myVar2 because it
              ///< spans multiple lines.

Class Example

/**
 * @brief
 *   A brief description of HolyHandGrenade.
 *
 * @details
 *   An even more detailed description of HolyHandGrenade.
 */
class HolyHandGrenade
{
private:
  int grenadeSize;   ///< Specifies if you want a large or small grenade
 
public:
  /**
   * @brief
   *   Hurl thine Holy Hand Grenade towards thy foe.
   *
   * @details
   *   Mercifully blows thine enemies to tiny bits.
   *
   * @param[in] count The number of the counting.
   */
  void hurl(int count);
 
  ...
};


Function and Method Comments

Every function should have a @brief section and, if appropriate, a @detail section that describes the function more in-depth.

Every parameter should be commented. Please try to use the direction attribute of the @param command ([in], [out], [in,out]).

If multiple return values are possible, it is preferable to use @retval to define each possible value that may be returned instead of @return. If there are many return values, or you just want to summarize what is returned, use @return to describe the return value.

Example:

/**
 * @brief
 *   Return the sum of two positive integers.
 *
 * @details
 *   Adds x and y and returns the result in z.
 *
 * @param[in] x First integer
 * @param[in] y Second integer
 * @param[out] z Holds the result of x+y
 *
 * @retval 0 success
 * @retval 1 failure, ints were not positive
 */
int sum(int x, int y, int *z)
{
  if (x < 0 || y < 0)
    return 1;
 
  *z = x + y;
 
  return 0;
}

Formatting

Line Length

Each line of text in your code should be at most 100 characters long.

Exception: if a comment line contains an example command or a literal URL longer than 100 characters, that line may be longer than 100 characters for ease of cut and paste.

Exception: an #include statement with a long path may exceed 100 columns. Try to avoid situations where this becomes necessary.

Exception: you needn't be concerned about header guards that exceed the maximum length.

Spaces Vs. Tabs

Use only spaces, and indent 2 spaces at a time. Do not use tabs in your code. You should set your editor to emit spaces when you hit the tab key.

Please fix indention in old code. It is a boring thing to do, but is incredibly valuable. When someone looks at code, they will send in patches based on what they see. Lets make it so the code looks identical.

vim

A vimrc collection that does our style can be found here: http://hg.tangent.org/vimrc

emacs

Elisp for .emacs can be found here: Emacs Style

No tabs are to be used in any files except Makefile.am files There you should lead off with a tab but complete indention with spaces.

Brace Placement

for/while loops:

for (...)
{
  foo()
}

do/while loops:

do
{
  foo()
} while (...);

For if/else place the else on a separate line from the braces:

if (something)
{
  something();
}
else
{
  something_else();
}

switch statements have the first { on their own line, and each case should line up with the switch:

switch (...)
{
case X:
  foo();
  break;
 
case Y:
  break;
}

Do NOT put {} around each case statement, this breaks the ability to nest switch with if/while/for which is useful during some state loops.

If you find that you are commenting a section of code feel free to use this style:

/* Some explanation */
{
  something()
}

In general it is better to be more verbose. Verbose code has a higher chance of surviving code rewrites since the next developer will understand it.

Function Declarations and Definitions

Function Calls

Conditionals

Instead of something together like this:

if (a == b && c == j || A)
  do_something();

Do it like:

if (((a == b) && (c == j)) || A )
   do_something();

Be generous with your use of parentheses. If I see them, then I know you knew what you were doing and I do not have to worry if you really understood operator precedent.

Loops and Switch Statements

When you use a for loop to iterate across something and do not actually do anything in the for loop (for instance, if you just want to walk an array or list of pointers): do this:

for () {};

or

for () {/* Do nothing */};

DO NOT do this:

for ();

Why? When you have an empty body. It gives a hint that you really did want just the for to loop.

Please do not use "i" as an iterator in for loops. I have old eyes...use x or spell out a variable. (Don't know who write this??)

Pointer and Reference Expressions

When declaring a pointer variable or argument, place the asterisk adjacent to the variable name. For instance:

string *foo;

Use NULL when referring to the null pointer, not 0.

When declaring a reference variable or argument, place the ampersand adjacent to the variable name. For instance:

string &foo;

Boolean Expressions

Return Values

No parentheses should be used around a simple return type. For example, the following is incorrect:

return(1);

It should be:

return 1;

Parentheses are encouraged around more complex expressions. For example:

return (x == MY_TYPE);

A space should always be present between the return and the expression that is being returned.

Ignoring return types

Generally, return types of a function should not be ignored, however, if you do ignore the return, do:

(void)func();

This indicates explicitly that you are ignoring the return and know that you are ignoring the return. This will be discouraged.

Variable Initialization

When assigning please use MySQL style (no space before equals sign, one space after):

x= 4;

It is easy to search for.

Initializer Lists

Initializer lists should be preferred to assignment in constructors in all cases.

Namespace Formatting

Other C++ Features

Assert

Use standard assert() for now. We have an option in the configure.ac file to turn this off for production uses. In general you should be liberal with your use of assert().

You should never put code with side effects required for normal operation in an assert.

Exceptions

What is the standard on exceptions???

Casting

Use C++ casts like static_cast<>(). For non-pointer casting (like with ints) use the form int y= int(x); rather than C-style cast int y= (int)x;

Excessive casting probably means bad design somewhere, so investigate if the source or target variable are typed correctly.

Preincrement and Predecrement

Use prefix form (++iter) of the increment and decrement operators with iterators and other template objects.

A fairly good explanation why.

Use of const

Use const whenever it makes sense to do so. const variables, data members, methods and arguments add a level of compile-time type checking; it is better to detect errors as soon as possible. It may make sense to use const in the following scenarios:

0 and NULL

Use 0 for integers, 0.0 for reals, NULL for pointers, and '\0' for chars.

Preprocessor Macros

Prefer inline functions, enums, and const variables to macros.

File Organization

Class/Structure File Conventions

All new classes get their own .h and .cc files. We will need to pull apart the mess that exists today, but that is a long term goal.

Linking

Do not use ../ linking in Makefile.am to reuse a a single object from another library. If you need to link to the library, then link to the library. Also, do not create symbolic links between libraries.

Directory Naming

Everything in the code is an item for the potential to have plugins. We will keep a clean naming scheme for this reason.

For the server the naming is "drizzled"

So an install will be: /usr/local/include/drizzled/

Client library: /usr/local/include/libdrizzle

If we add extensions to the command line library they will go into "drizzle"

Includes that will be installed need to be written like:

  1. include "drizzled/field/blob.h"

TODO: Work out "error" condition in includes if a build of the server uses an "include" from the install path (aka we want to make sure we only use the includes in our directory).

C++ Standards

The codebase is C++. Code should be written in idiomatic C++ rather than in idiomatic C whenever possible. In the absence of specific guidelines from us to the contrary, "Effective C++" by Scott Meyers is an excellent set of best-practices for C++ and should be followed.

Other

Avoid #ifdef except for real portability needs.

Never conditionally define a member variable or method of a struct/class using #ifdefs

Structures should be typedef'ed as name_st.

If it's a class, use a class not a struct.

Use enum, not define, for sets of related constants.

Use static const, not define, for single constants.

Site generously hosted by SoftLayer Technologies