-
Notifications
You must be signed in to change notification settings - Fork 73
NamingConventions
#NamingConventions
Prefer to follow the following rules for naming identifiers.
Identifier type | Example | Naming |
---|---|---|
Functions and methods | DoSomething() |
Camel case, begin with a capital. This applies equally to methods, global "free" functions and file scope static functions |
Classes, structs and namespaces | class FooBar |
Camel case, begin with a capital |
Typedefs and template renames | typedef ... RenamedType |
Camel case, begin with a capital |
Member variables | _myName |
Begin with an underscore, and then a lower case letter |
Function-scope variables and function parameters | someVariable |
Camel case, begin with a lower case letter |
Static member variables | s_instance |
Begin with a lower case 's', then an underscore, and then a lower case letter |
Global-scope variables and file-scope static variables | g_theWorldManager |
Begin with a lower case 'g', then an underscore, and then a lower case letter. |
##Examples
The following is well formatted code:
#include <algorithm>
namespace Examples { namespace Naming
{
/// <summary>Typical XLE class</summary>
/// This is an example of what a typical XLE class
/// might look like
/// <example>
/// <code>\code
/// XWing wingLeader;
/// for (auto i=0u; i < XWing::GetFoilCount(); ++i) {
/// wingLeader.OpenFoils(i);
/// }
/// wingLeader.CommenceStrafingRun();
/// \endcode</code>
/// </example>
class XWing
{
public:
const std::string& GetSquadName() const never_throws { return _squadName; }
void OpenFoils(unsigned foilIndex);
void CommenceStrafingRun();
static unsigned GetFoilCount() { return _foilCount; }
XWing(const char squadName[]);
~XWing();
private:
std::string _squadName;
struct FoilState
{
enum Enum { Closed, Open };
};
static const unsigned s_foilCount = 4;
FoilState::Enum _foilState[s_foilCount];
};
inline XWing::XWing(const char squadName[])
: _squadName(squadName)
{
std::fill(_foilState, &_foilState[dimof(_foilState)], FoilState::Closed);
}
}}
The following example contains mistakes and incorrect formatting:
namespace BadExamples
{
// Use a capital letter for a class identifier
class something {}; // BAD!
// Avoid identifiers that look like they are something else.
// This is a class, but it's using the naming convention for a member viable
class _itLooksLikeAMember {}; // BAD!
// Global scope variable should begin with "g_"
// Readers will be expecting us to follow the standards,
// so violations are particularly confusing.
_itLooksLikeAMember whatsGoingOn; // BAD!
class SomeClass // OK
{
public:
// Underscore followed by a capital letter is reserved by the language standard.
// Use a lower case letter after the underscore
int _BadlyFormed; // BAD
};
}
##Rationale
Generally I prefer to avoid too many rules and restrictions for naming and layout conventions. However, there are some good advantages to this scheme.
###Clear member variable distinction
It's handy to distinguish between member variables and local function-scope variables. It can often make a complex method much easier to understand.
This is particularly useful in constructors, where often we want to initialise a member with the same name as a parameter.
Prepending a underscore is the least intrusive way to clearly distinguish member variables. However, if we begin an identifier with an underscore, the next letter should be a lower case letter.
More specifically, the second character must not be a upper case letter, or another underscore. Both these cases are reserved by the language standard.
###Clearly identify static member variables and globals
I find it useful to be particularly explicit when using static member variables, globals and file scope static variables. Usually we don't want to confuse these with local scope variables and normal member variables. We don't use them frequently, so let's just be explicit about it.
###Exceptional cases
In rare cases, some exceptions are made
- some classes and functions are designed to replace, or "feel like" similar classes in the standard library
- An example is
class intrusive_ptr
. This is designed to match the behaviour of std::shared_ptr and std::unique_ptr. Therefore, it uses similar naming conventions - There are also some macro #defines that are intended to behave like language keywords
- Some examples are:
never_throws
,dll_export
,thread_local
,dimof
- These follow the naming conventions of C++ keywords to better fit in with their purposes. Syntax highlighting and our knowledge of the language should make it adequately clear that they extensions to the language
- In some cases (eg,
thread_local
) these can be macros under some compilers, but built in keywords under others - Some classes may need to meet the template requirements for compatibility with standard library types. A custom allocator is a good example. In these cases, we're forced to use the standard library naming conventions (eg, for a
value_type
typedef, orallocate()
method) - Sometimes we need to make exceptions in order build certain meta-programming constructs, or some reusable template interface.
##Other cases
Normally template parameters should use the same formatting as classes and typedefs (both for typename and scalar type parameters).
template <typename Type, int Count>
Type SomeFunction();