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?
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):
In this context, the meaning of the number 0 is clear enough. I suppose you could define
Another example might be if you are trying to determine if a number is even or odd. Writing:
is not as strange as:
Testing negative numbers as
also feels weird to me, I'd much rather see
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:
which is clearer (and the recommended practice ) than say
as I'm unlikely to ever need to change the length (and can always compare to the
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
Sure I could name
or worse define
I would suggest three key factors in deciding whether something should be a constant declaration:
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
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.
It is obvious zero means absence. I find 0 easier to understand than a variable named "absenceValue".
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.
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