Magic Number (programming) - Unnamed Numerical Constants

Unnamed Numerical Constants

The term magic number or magic constant also refers to the programming practice of using numbers directly in source code. This has been referred to as breaking one of the oldest rules of programming, dating back to the COBOL, FORTRAN and PL/1 manuals of the 1960s. The use of unnamed magic numbers in code obscures the developers' intent in choosing that number, increases opportunities for subtle errors (e.g. is every digit correct in 3.14159265358979323846 and is this equal to 3.14159?) and makes it more difficult for the program to be adapted and extended in the future. Replacing all significant magic numbers with named constants makes programs easier to read, understand and maintain.

Names chosen should be meaningful in terms of the domain. It is easy to imagine nonsense like int EIGHT = 16 resulting when NUMBER_OF_BITS might have been a better choice of name in the first place.

The problems associated with magic 'numbers' described above are not limited to numerical types and the term is also applied to other data types where declaring a named constant would be more flexible and communicative. Thus, declaring const string testUserName = "John" is better than several occurrences of the 'magic number' "John" in a test suite.

For example, if it is required to randomly shuffle the values in an array representing a standard pack of playing cards, this pseudocode will do the job:

for i from 1 to 52 j := i + randomInt(53 - i) - 1 a.swapEntries(i, j)

where a is an array object, the function randomInt(x) chooses a random integer between 1 to x, inclusive, and swapEntries(i, j) swaps the ith and jth entries in the array. In the preceding example, 52 is a magic number. It is considered better programming style to write the following:

constant int deckSize := 52 for i from 1 to deckSize j := i + randomInt(deckSize + 1 - i) - 1 a.swapEntries(i, j)

This is preferable for several reasons:

  • It is easier to read and understand. A programmer reading the first example might wonder, What does the number 52 mean here? Why 52? The programmer might infer the meaning after reading the code carefully, but it's not obvious. Magic numbers become particularly confusing when the same number is used for different purposes in one section of code.
  • It is easier to alter the value of the number, as it is not duplicated. Changing the value of a magic number is error-prone, because the same value is often used several times in different places within a program. Also, if two semantically distinct variables or numbers have the same value they may be accidentally both edited together. To modify the first example to shuffle a Tarot deck, which has 78 cards, a programmer might naively replace every instance of 52 in the program with 78. This would cause two problems. First, it would miss the value 53 on the second line of the example, which would cause the algorithm to fail in a subtle way. Second, it would likely replace the characters "52" everywhere, regardless of whether they refer to the deck size or to something else entirely, which could introduce bugs. By contrast, changing the value of the deckSize variable in the second example would be a simple, one-line change.
  • The declarations of "magic number" variables are placed together, usually at the top of a function or file, facilitating their review and change.
  • It facilitates parameterization. For example, to generalize the above example into a procedure that shuffles a deck of any number of cards, it would be sufficient to turn deckSize into a parameter of that procedure. The first example would require several changes, perhaps:
function shuffle (int deckSize) for i from 1 to deckSize j := i + randomInt(deckSize + 1 - i) - 1 a.swapEntries(i, j)
  • It helps detect typos. Using a variable (instead of a literal) takes advantage of a compiler's checking. Accidentally typing "62" instead of "52" would go undetected, whereas typing "dekSize" instead of "deckSize" would result in the compiler's warning that dekSize is undeclared.
  • It can reduce typing in some IDEs. If an IDE supports code completion, it will fill in most of the variable's name from the first few letters.

Disadvantages are:

  • It hurts the locality and comprehensibility of the code. Putting the 52 in a possibly distant place means that to understand the workings of the for loop completely (for example to estimate the run-time of the loop) one must track down the definition and verify that it is the expected number.
  • It makes the code more complex. An increase in complexity may be justified if there is some likelihood of confusion about the constant, or if there is a likelihood the constant may need to be changed, such as reuse of a shuffling routine for other card games.
  • It may be slower for the CPU to process the expression "deckSize + 1" than the expression "53". However, most modern compilers and interpreters are capable of using the fact that the variable "deckSize" has been declared as a constant and pre-calculate the value 53 in the compiled code. There is therefore usually no speed advantage to using magic numbers in code.
  • It can increase the line length of the source code, forcing lines to be broken up if many constants are used on the same line.
  • It can make debugging more difficult, especially on systems where the debugger doesn't display the values of constants.

Read more about this topic:  Magic Number (programming)

Famous quotes containing the word numerical:

    There is a genius of a nation, which is not to be found in the numerical citizens, but which characterizes the society.
    Ralph Waldo Emerson (1803–1882)