Naming Rules


[nr01] One of our main activities as programmers is giving names to things. The most important principle we follow is that meaningful names are always preferred. Don't do this:

   SInt32 xx;
   SInt32 xx1;
   SInt32 xx2;

instead, prefer meaningful variable names:

   SInt32 elementCount;
   SInt32 xPosition;
   SInt32 currentTemperature;

However, it's not to be suggested that length alone is the important metric when choosing identifier names -- clarity, memorability and consistency throughout a project are far more important. Generally, the shorter an identifier's life (or the more localized its scope), the shorter its name needs to be. For example, the traditional use of i and j as loop index names, or p for pointer values are idiomatic and their use should not be discouraged.

Capitalization

[nr02] By establishing a simple set of capitalization standards, we can eliminate large amounts of time wasted trying to remember how to spell an identifier declared elsewhere in the source. Instead of using the words_separated_by_underscores style found in many programming textbooks, all identifiers in Art & Logic programs use one of several mixed case formats, as outlined below. (See also Reserved Prefixes)

  • [nr03] Local variables and function parameters always begin with a lowercase letter. Subsequent words in the identifier are capitalized:

   fileName
   xPosition

  • [nr04] Class member variables always begin with a lowercase f followed by a single uppercase letter:

      fFileName
      fStartTime
  • [nr05] Class members in any language where member variables may only be accessed by providing an explicit $this or self reference should omit the f prefix, since the language is enforcing the disambiguation for us.

  • [nr06] Fields in simple C structures always begin with a lowercase letter, with subsequent words capitalized:

      struct Point
      {
         SInt32   xPos;
         SInt32   yPos;
      };
  • Since the elements inside this structure may only be accessed using an instance of the structure (or a pointer to the structure) there's no ambiguity to be removed by an additional naming convention.
  • [nr07] In Java, class methods (other than a class' constructor) begin with a lowercase letter, and additional words in the method name are capitalized. All method calls are made to an explicit object; calls to another method of the current object are made by specifying this:

      public int getArea()
      {
         return this.getWidth() * this.getHeight();
      }
  • [nr07] In Objective-C, init methods and dealloc may begin with a lowercase letter, as this capitalization is significant to the code analyzer provided by Apple. Other (non-init) methods should obey the general A&L capitalization rule that follows.

  • [nr07] In all other OO languages, method/member function names begin with an uppercase letter, and all subsequent words are also capitalized. Calls to member functions in the current object are made through the appropriate this-> or self. pointer:

      public:
         SInt32 GetArea()
         {
            return this->GetWidth() * this->GetHeight();
         }
  • or:
      def GetArea(self):
         return self.GetWidth() * self.GetHeight()
  • [nr08] New types that are not classes (C structs, enumerated types, typedefs, etc.) are named using a leading uppercase letter, with subsequent words also capitalized, like:

      enum Flavor
      {
         kVanilla = 0,     // always initialize the first 
         kChocolate,
         kCilantro,
         kDurian           // note -- no comma on the last enum!
      };

      typedef unsigned short int IoRegister;
  • [nr09] Identifiers in A&L programs should not contain underscores (the obvious exceptions here are 'magic method' identifiers in Python which must contain leading and trailing double underscores, and when using the single and double leading underscore visibility modifiers in Python).

  • [nr10] Avoid using two (or more) consecutive uppercase letters in an identifier. For example, when using an acronym or product name in an identifier, ignore the capitalization used elsewhere; a member variable holding some sort of data about something at NASA should be called fNasaData, not fNASAData. There are a few exceptions to this rule:

    • [nr11] C++ class names are always prefixed with an uppercase A, followed by another uppercase letter, like AUsefulClass.

    • [nr12] The standard Art & Logic C/C++ integral typedefs SInt* and UInt*.

    • [nr13] COM or Java interfaces are named by prefixing the interface name with a capital I, like ISerializable.

  • [nr14] Ignore unusual capitalization found in product, technology or company names. For example, when working on a project spelled "megaSURF", any identifiers in the program that incorporate the project name should be capitalized like:

      class AMegaSurfApp;

      void About(SInt32 megaSurfVersion);

Abbreviations

[nr15] Avoid using abbreviations when naming things in source code. When abbreviations are used in source, it's important to take care to prevent confusion arising from oddly chosen abbreviations, or from inconsistent use of them. For example, if you have decided that index is just too many letters to type as part of identifier names, decide once for the project whether you're going to spell it indx or idx and use that consistently throughout the project's code.

Attempt to limit abbreviations to those that are obvious, common, or idiomatic to the project.

Hungarian Notation

[nr16] We do not use Hungarian notation at Art & Logic.

Reserved Prefixes

[nr17] To avoid name clashes, we use a set of reserved prefixes that indicate the use, scope, or function of the identifier. The letter following the prefix must be upper case. Note that this list of prefixes includes entries that are not applicable in all languages that we use; there are no global variables or functions in Java, for example, so the g and u prefixes listed below are not used. (See also Capitalization)

A

[nr18] All class names should begin with a capital letter "A", followed immediately by another capital letter (or digit) that begins the "real" name of the class.

f

[nr19] Class member variables are always prefixed with a lowercase "f", followed by an uppercase letter beginning the variable name.

g

[nr20] Global variables are prefixed with a lowercase "g", followed by an uppercase letter beginning the variable name. Avoid using global variables.

h_

[nr21] Recursive inclusion of C or C++ header files is prevented by wrapping the contents of all header files inside blocks of code like:

      #ifndef h_FileName
      #define h_FileName

      //
      //    contents of file here...
      //

      #endif   // this must be the last line in the header file.
  • The identifier that follows the h_ prefix must be the name of the file, without its file extension.

    Note that this is the only exception to the rule that A&L identifiers never contain underscores. In earlier versions of the A&L Style Guide, this prefix was just h, consistent with the format used for all of the other reserved prefixes. This exception was prompted by problems encountered when working with source code from outside Art & Logic that followed the Microsoft-style Hungarian convention that a variable prefixed with an h was a handle to something. After tiring of tracking down and fixing clashes between our include guard macro hSomething and a variable also named hSomething, we decided that altering this prefix was more likely to be a workable solution to the problem than convincing the rest of the world to stop using Hungarian notation.

I

[nr22] When creating interface definitions for COM or Java, use the traditional I prefix.

k

[nr23] All identifiers that refer to constant values should be prefixed with a lowercase k, whether they are declared using the C/C++ const keyword, as part of an enumerated type, the Java final keyword, or other equivalent mechanism.

  • Note that the k prefix is only intended to apply to identifiers that are constant at compile-time. Don't write code like: SomeFunc(const std::string& kParam);

    This should instead be: SomeFunc(const std::string& param);

m

[nr24] Any C or C++ preprocessor macro that is called as if it were a function should be prefixed with a lowercase m.

q

[nr25] C/C++ compiler macros used to conditionally compile out sections of code should be prefixed with a lowercase q. Note that even though Java doesn't have preprocessor-based conditional compilation, javac and other Java compilers will omit any code from the binary that it can statically deduce will never be executed, accomplishing the same effect. So in Java, code like:

      private static final qDebug = false;

      if (qDebug)
      {
         // useful debug-only code here...
      }
  • is the logical equivalent of C/C++ code like:
      #define qDebug 0

      #if qDebug
         // useful debug-only code here...
      #endif

By the same token, dynamic or interpreted languages like Python or PHP, while not having a separate compilation step, should still use 'q'-prefixed variables to indicate that those variables are being used to control the execution of blocks of code where that variable won't change during the course of an invocation of an application.

r

[nr26] Resource identifiers are prefixed with a lowercase r. Resource identifiers may go by different names on different operating systems or development environments. For our purposes, a resource identifier is any name that refers to a user interface component that is obtained from a resource manager, like any Win32 or Macintosh UI dialog box items or menus.

s

[nr27] Static variables are prefixed with a lowercase s. In C++, prefer to use anonymous namespaces to create file-scope variables.

u

[nr28] C++ global functions are prefixed with a lowercase u. Avoid using global functions. Instead, group related functions into classes, using static member functions if necessary. Obvious exceptions to this rule are non-member operators and free functions that are logically part of a class' interface, but are not members. According to Sutter's "Interface Principle":

  • For a class X, all functions including free functions that both

  • "Mention" X

  • Are "supplied with" X

    Are logically part of X, because they form part of the interface of X.

Any time you write a standalone function that is in global scope and is not clearly part of a class' interface, it should use the u prefix. Free functions that are contained within a namespace are not global, and therefore do not need to use this prefix.