Named Constants

From SelfDocumentingCode.

Use named constants.

Rationale:

Hard-coded numbers that appear out of nowhere in code mean nothing to anybody but the initial programmer. Reading them is almost as fun as reading disassembled output. These so-called "magic numbers" that appear in code are unnecessary in most modern languages.

When these numbers have complicated origins (like the transcendental number e) or are subject to random changes (like the size of a buffer), it is a much better idea to a) give them a name, b) put their definitions in a central area (relative to their context, like the top of a file or class definition). This way, you can lend meaning to the code and improve flexibility.

It has been said that the only "good" constants are zero, one and infinity (ZeroOneInfinityRule).

Refactoring:

See ReplaceMagicNumberWithSymbolicConstant.

Arguments:

"You mean I have to come up with a name for every number?"

No, not always. Typically, it is useless to come up with a name for "2" in the expression "iBufferSize *= 2;" if you preface it with a comment along the lines of "Doubling the buffer size is the more efficient method of growing a buffer." Although, even then, I'd consider making a constant named something like s_kiGROW_FACTOR. You may not even need a comment then.

"I don't want to type that much."

It's less fun to search and replace through all the code when you have to change the buffer size. This also has a high probability of introducing defects into the codebase.

Exceptions:

Some formulas, especially mathematical formulas, are well known or simple to understand. In these cases, you probably don't need named constants. But commenting is always a good idea!

Also, standard values like the NUL ('\0' in C) character for ASCIIZ strings probably don't need named constants. But random Unicode values like \uB2A8 in Java probably need them. -- EricJablow

Examples:

The buffer size above is a good example.

It's typically a good idea to place all constants at the top of a class definition in either the implicit private section or at the top of the public section. The reason being is that knowledge of these constants is very important when using and implementing the class, so they get top billing (See also EmphasizeImportantInformation. For example:

 class Foo
 {
     static const int s_kiBUFFER_SIZE;
     static const char *s_kszDEVICE;

public: static const int s_kiINFINITE; ...

protected: ... private: ... };

const int Foo::s_kiBUFFER_SIZE = 4096; const char *Foo::s_kszDEVICE = "prn"; const int Foo::s_kiINFINITE = -1;
This also has the benefit of scoping the names thus skirting the name collision problem. In a standard C++ compiler, you can even go static const int s_kiBufferSize = 4096; right in the declaration, although this is unavailable in old versions of MSVC++.

Another good way to declare a constant is to use an (anonymous) enum ala

 enum { INFINITE = -1 };
Although this will likely not compile in MSVC++ in any real project as the global namespace has been polluted by the preprocessor (INFINITE is declared in the Windows headers).


Note that this will also fail to compile in any conformant C compiler: C90 does not permit anonymous enumeration declarations. I'm not sure if this was fixed in C99 or not, not having a copy of the Standard to hand. Since the Windows SDK (which is where INFINITE is declared) is targeted at both C and C++ programmers, use of C++ features such as anonymous enums might not be an entirely sensible plan. My gripe, of course, is that the SDK uses:

'nash' The above is blantently false. Ansi/c90 specifically allow anonymous enums. In K&R the many examples use anonymous enums. Additionally the grammer states:

 enum identifieropt { enumerator-list }
(the opt is a subscript in the grammer), with the opt indicating that the identifier field is optional. So C90 does allow anonymous enums, and the authors encourage it 'end nash'

#define INFINITE -1

rather than:

static const int INFINITE = -1;

but that's because I am not of the opinion that PreprocessorsAreNotEvil. -- JonKale


Don't get me started on Microsoft and the preprocessor!!!!!


An alternative to NamedConstants is to place the constant in a single small method. Give the methods the same name as the NamedConstants would have had. (This is NamedConstants in a way, since most of the difference is in a little syntax).

I'm using this more and more in JavaLanguage and I've heard that it is the only way to do it in SmallTalk, which lacks NamedConstants(?) -- AndersBengtsson

You can use globals in Smalltalk. e.g. INFINITE := -1.

I never did see that feature when trying SmallTalk a few years back. Now I'm confused... :-) -- AndersBengtsson

Globals in Smalltalk are placed in the Smalltalk dictionary, i.e.:

  Smalltalk at: #INFINITE put: -1
Less global "globals" can be placed in pool dictionaries.


Even better than named constants is to use named functions. From above, if you create the following function (assuming a CBuffer class):

inline void CBuffer::Grow() {

    iBufferSize *= 2;
};

If you take this approach raw numbers are not only acceptable, but usually better than named constants! The only exception is when you need to use the constant in more than one place, such as in a constructor and in some bounds test. -- WayneMack


CategoryCodingIssues


EditText of this page (last edited January 28, 2009) or FindPage with title or text search