Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

So every number in the code that we are sending to a method as an argument is considered as a Magic Number? To me, it shouldn't. I think if some number is let's say it is for minimum length of user name and we start using "6" in the code...then yeah we have a maintenance problem and here "6" is a magic number....but if we are calling a method that one of its arguments accept an integer for example as the ith member of a collection and then we pass "0" to that method call, in this case I don't see that "0" as a magic number. What do you think?

share|improve this question
4  
In your example, what does the 0 represent? –  Aaron Kurtzhals Jan 8 '13 at 18:31
2  
In the case you illustrate, that "0" has no magical properties whatsoever. –  user61852 Jan 8 '13 at 20:21
add comment

5 Answers 5

up vote 33 down vote accepted

If the meaning of the number is very clear in the context, I don't think it's a "magic number" problem.

Exmaple: Let's say you're trying to get the substring of a string, from the begining to some token and the code looks like this (imaginary language and library):

s := substring(big_string,0,findFirstOccurence(SOME_TOKEN,big_string));

In this context, the meaning of the number 0 is clear enough. I suppose you could define START_OF_SUBSTRING and set it to 0, but in this case I think it would be overkill (although it would be the correct approach if you knew that the start of your substring might not be 0, but that depends on the specifics of your situation).

Another example might be if you are trying to determine if a number is even or odd. Writing:

isEven := x % 2;

is not as strange as:

TWO := 2;
isEven := x % TWO;

Testing negative numbers as

MINUS_ONE := -1;
isNegativeInt := i <= MINUS_ONE;

also feels weird to me, I'd much rather see

isNegativeInt := i <= -1;
share|improve this answer
3  
To throw another example on there, in code where you're explicitly working with degrees on a circle, it would be fair to use a number such as 360 to mark a full rotation with the understanding that most people will know what that means (though this is a case where it wouldn't hurt to provide a constant) –  KChaloux Jan 8 '13 at 19:00
8  
KChaloux: If I could, I would -1 your comment. 360 is a magic number. If 360 happens to be a value for another constant, then you have 2 sets for 360 that are unrelated and indistinguishable. Junior comes along, go "That is a magic number", global search and replace 360 with "Degrees_in_Circle", run all unit and regression tests, all pass - delivers code fix. Code now a dogs breakfast, and we all know what happens to that after a short time....... –  mattnz Jan 8 '13 at 20:17
3  
@mattnz: Hopefully that kind of large-scale code change would be quickly caught (hopefully during code review, if they're that junior) long before it ever got into production. I think someone who would do that in that context would probably also replace 0 in the context of the my substring example. In which case, this might be the least amount of damage they can cause. It's been a long time since I did any coding that did geometric calculations, but generally, the values 15, 30, 45, 60, 90, 180, 360 were constants that were accepted. I've never seen anyone define FIFTEEN_DEGREES,... –  FrustratedWithFormsDesigner Jan 8 '13 at 20:29
5  
@KChaloux The example may actually fall apart if there's a shift from Degrees to Radians. By 360, you are expressing 1 complete rotation. Since there are multiple representations for the same value, it should be pulled out. Especially considering 360PI could look the same as 2PI (180 rotations but still pointing the same direction in the end), or 360 rotations the same as 1 rotation, but side effects may be different. –  Chris Jan 8 '13 at 21:36
7  
A bit of a straw man there, TWO and MINUS_ONE are utterly bad because replacing a magic number with its rendering in text is OF COURSE idiotic. The name of the constant has to convey its meaning. Except your examples are about fundamental facts about numbers, closely tied to just those specific numbers, so there isn't really any meaning beyond that. –  Michael Borgwardt Jan 10 '13 at 16:15
show 4 more comments

This, as all principles, is a matter of degree. Generally speaking, number literals in source code are more suspect the larger they are. A maximum length like 10 or a memory address like 0x587FB0 are obviously bad practice - it is almost certain that sooner or later you will have to repeat these values more than once, creating a risk of incompatibility and subtle errors introduced in places that weren't changed.

0 is at the other end of the scale; it is still suspect but not quite as much. Are you using 0 as a sentinel value? Then you should probably use a symbolic constant instead, just because the constant can explain what it means. Is it an extremely entrenched cultural agreement such as "0 means successful completion"? That's probably OK. Does it mean "the first item in a collection"? That may be harmless, but if there is an alternate method such as first() I'd probably prefer that.

share|improve this answer
add comment
bool hasApples = apples > 0;

It is obvious zero means absence. I find 0 easier to understand than a variable named "absenceValue".


for(int i=0; i < arr.length; i++)

It's obvious 0 is the starting position. I would be confused by a variable named "firstPosition". Such a variable would make me wonder if the starting position could change.

share|improve this answer
add comment

I would suggest three key factors in deciding whether something should be a constant declaration:

  1. Is the number something that is precisely and concisely representable
  2. Are there any plausible scenarios under which the value would have to change, but the code would not have to be rewritten
  3. Would someone who sees the number be apt to recognize it more quickly or less quickly than someone who sees a named constant

Something like pi should probably be written as a named constant, rather than as a numeric literal, since a numeric literal is apt to be needlessly verbose, needlessly imprecise, or both. Something like the number of slots in a cache should likely be a named constant (though see note below) to allow for the possibility of expanding the cache without having to modify all the code that uses it. Things like the numbers "4", "28", and "29" in the statement if ((year % 4)==0) FebruaryDays = 29; else FebruaryDays = 28; should probably not be named constants, since the expression is almost certainly more readable than if ((year % YearsBetweenLeapYears)==0) FebruaryDays = FebruaryDaysInLeapYear; else FebruaryDays = FebruaryDaysInNonLeapYear;. Note that the maintainers of standards have indicated that the length of February 2100 in that year will not match the above formula, but I would recommend not handling that case unless it would be the only impediment to correctly handling such dates (i.e. the code won't get tripped by integer overflow or other such problems).

An important caveat with rule #2 is that in some cases code may rely upon hard-coded numbers in a way which cannot readily be represented by a named constant. For example, a method which computes a cross product of two vectors passed as discrete parameters will only be meaningful when used on three-dimensional vectors. The required number of dimensions is not a value that could meaningfully be changed without completely rewriting the routine. Even if one foresaw a possible need for computing the cross product of three 4-dimensional vectors, using a named constant for the value "3" would do little to make it easier to satisfy that need.

share|improve this answer
add comment

Every unnamed number that's not immediately obvious from context is a magic number. Its a little silly to define numbers that have meaning that is immediately obvious from context.

In django (python web framework), I may define some database field with a raw number like:

firstname = models.CharField(max_length=40)
middlename = models.CharField(max_length=40)
lastname =  models.CharField(max_length=40) 

which is clearer (and the recommended practice ) than say

MAX_LENGTH_NAME = 40
...
firstname = models.CharField(max_length=MAX_LENGTH_NAME)
middlename = models.CharField(max_length=MAX_LENGTH_NAME)
lastname =  models.CharField(max_length=MAX_LENGTH_NAME) 

as I'm unlikely to ever need to change the length (and can always compare to the max_length of the field). If I do need to change the length of the field after initially deploying the application, I need to change it in exactly one location per field in my django code, and then additionally write a migration to change the schema of the DB. If I ever need to reference max_length of a defined field of a type of object, I can do it directly -- if those fields were defining a Person class, I can use Person._meta.get_field('firstname').max_length to obtain the max_length being used (which is defined in one place). The fact that the same 40 was used for multiple fields is irrelevant as I may want to change them independently. The length of firstname should never depend on the length of middlename or lastname; they are separate values and can change independently.

Often array indices can use unnamed numbers; like if I have a CSV file of data that I want to put in a python dictionary, with the first element in the row as the dictionary key I would write:

mydict = {}
for row in csv.reader(f):
    mydict[row[0]] = row[1:]

Sure I could name index_column = 0 and do something like:

index_col = 0
mydict = {}
for row in csv.reader(f):
    mydict[row[index_col]] = row[:index_col] + row[index_col+1:]

or worse define after_index_col = index_col + 1 to get rid of the index_col+1, but that doesn't make the code clearer in my view. Also, if I give the index_col a name, I better make the code work even if the column is not 0 (hence the row[:index_col] + part).

share|improve this answer
6  
Actually, max_lngth=40 vs. max_length=MAX_LENGTH_NAME is a classic examlple of a magic number that screams to be a symbol. The day will come when you want to support 45 character names, and now every use of "40" is suspect and must be carefully examined. –  Ross Patterson Jan 9 '13 at 0:21
1  
@RossPatterson - This is not C where we constantly compare against a global var MAX_ARRAY_SIZE, but a decent web framework. The only place that the magic number comes up is where you declare the database model; everything else is compared against this value (e.g., 40 appears nowhere else in the code). Also note, you can't change this variable easily without doing schema migrations as its tied to a DB. If I wanted to change to say 1 character middle names its immediately obvious the one place to change in the code 40 to 1. You have to think of context. –  dr jimbob Jan 9 '13 at 7:33
2  
Sorry, you're wrong on two points. First, the OP asked a "programming practices" question that doesn't specify any language. They said "method", not "function", so let's presume something object-oriented, but that doesn't take us out of the realm of magic-numbered data. Second, if the magic number is baked into the database (e.g., the schema), then it's even worse to have it in code. The right thing to do is to get the magic almost-a-constant from its source - either the database itself or a schema module that centralizes all those constants-that-will-vary-over-the-code's-lifetime. –  Ross Patterson Jan 9 '13 at 11:58
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.