I just have a Numbers class I import into all my projects:
public final static int ZERO = 0;
public final static int ONE = 1;
public final static int TWO = 2;
public final static int THREE = 3;
public final static int FOUR = 4;
....
It can be fun with code like that to see if you can imagine situations where you could argue with a straight face that the code is OK.
public static String HTTP = "http";
An argument for this might be that it allows you to easily change to https by changing that one line, although then the name of the string would be misleading.
public static String COLON = ":";
public static String SLASH = "/";
These are harder. Maybe you don't want ":" and "/" to appear literally because for some reason you grep for ":" and "/" a lot looking for instances that are syntactically significant in your language and you got tired of hitting those characters in URL strings.
All of these potential excuses fall, though, to the objection that all three of those could have been rolled into a single string, with a sensible name like URL_COMMON_PREFIX:
public static String URL_COMMON_PREFIX = "http://";
"""A candidate for the title of "Strangest Thing in Computer Science" would be the fact that FORTRAN lets you change the value of what appear to be unalterable numbers. Plato would roll over in his grave.
I have heard rumors that later FORTRAN compilers had this "capability" designed out. But the venerable FORTRAN IV and FORTRAN 77 allowed you to do it"""
The primary purpose of the DATA statement is to give names to constants; instead of referring to pi as 3.141592653589793 at every appearance, the variable PI can be given that value with a DATA statement and used instead of the longer form of the constant.
This also simplifies modifying the program, should the value of pi change.
No one seems to be mentioning another use of the phrase "magic number" which isn't bad at all - numbers put in files to mark the file type. 0xCAFEBABE in java class files, for instance.
Unix even has "man 5 magic", which describes the format of the magic numbers file that the "file" command uses to determine the type of a file (executable, object code, shell script, etc.) from its first few characters.
My personal favorite magic numbers are the values that debuggers use to fill uninitialized memory, like 0xDEADBEEF, 0xBAADF00D, etc.
In my opinion there are two kinds of magic numbers:
* the first kind is the one most answers describe: an arbitrary number used in various places that may change at any moment. The size of a buffer for instance.
* the second kind are numbers that represent something very specific but not immediately obvious when reading the code: for instance in a device driver "read_register(base + DEVICE_STATUS)" is much clearer than "read_register(base + 0x3c)". In this case naming the magic number is useful even if it's used only once in the code. It acts as a comment basically.
I'd also add that sometimes adding too many levels of indirection is a bad thing, and in the (currently) top voted answer I prefer the original over the "fixed" version. Either you do the right thing and make MAX_PASSWORD_SIZE something meaningful or you might as well write "if (password.length() > 7)". It's clear, non ambiguous and (in the example) not reused anywhere. Defining a macro for that just hides poor code and forces me to go look for the definition in order to understand what's going on (while debugging for instance).
Agreed. All of the top 3 answers focus on the numbers being directly used in code which is not the real reason why magic numbers cause problems.
They are bad because of not being explained. A number directly used in code is not magic if it is properly commented. Granted, explaining it by making it a named constant is very often better (reusability), but a literal number that is merely commented is not "magic".
Also, it can be a good idea to yank out all of those into a separate config file. Although, it destroys locality, so it depends on the use case I guess.
I wouldn't move it into a config file unless you're also testing the code works correctly with different values. Otherwise it's just asking for trouble.
I was about to go into a rant about that moron that named its variables after Starwars characters and then left for a better paying gig, leaving his unmaintainable mess for others to careabout, but it would be unfair for me to project my own traumas into you. Besides... it was 2007, so I better learn to let go.
Instead, I am going to say that getting your software working is one important goal, perhaps the most important goal because by doing that you get the money and the social capital that let you keep going and accomplish the other goals, but it is not the only goal.
Other goals, such as maintainability, are important too, and they come with their own sets of requirements and constrains, often conflicting with those of other goals. If you want to call yourself a professional, you must recognize those conflicts and make deliberate tradeoffs based on local conditions, and never gratuitously undermine any set of goals just for the sake of it.
Or you can make a whole career out of bluffing and waving the "get shit done" mantra. Never keeping the same job long enough for the consequences of your own poor decisions to come back and bite you in the ass.
It isn't hard (actually it's pretty easy) to get in the habit of replacing magic numbers with named constants immediately. Any time you hardcode a number just name it instead, and on the line immediately above it define the constant with a "TODO: refactor to the right place" comment. That way when you're done with the current creative focus, you can go back and put it right. This fixing is great for boring meetings, warmup/rezoning time, and so on. Alternately just keep a bookmark to the #defines in your editor and go drop it in the right place immediately.
Doing this makes life convenient because magic numbers often turn out to be real problems - did you typo the number somewhere? Did you forget to update the magic in one spot? These bugs waste more time in hunts than they cost in "do it right immediately".
Once the software's working, and has been for several years, and it has become unmaintainable because lax guidelines let this stuff through, this sort of thing becomes your real problem.
Nah, ubiquitous session re-use, bad APIs, arbitrary data structures (e.g everything in complex sets of nested arrays), hardening of code against static analysis (e.g. database lookups to instantiate classes at runtime) rate way higher on my scale.
Local use of magic numbers (across 1 file) don't bother me any more, although I will recommend fixing them when I find them.
I once worked with a guy who thought like this. His work was a morass of hundreds-of-lines-long VB methods. And when it stopped working, it stopped working hard, and I had to pick up the pieces.
Good programming practices are not a distraction from getting it working. They're essential to keeping it working, even in the face of changing requirements and unanticipated circumstances.
I agree, but they should be guidelines, not rules. Messy code is one extreme, and having perfect-looking code is the other. Clearly there's a balance somewhere.
Because doing so is one of the many measures you can take to ensure your software is (and stays) easily maintainable. Getting your SW working is only really one stage of a product life cycle.
public final static int ZERO = 0; public final static int ONE = 1; public final static int TWO = 2; public final static int THREE = 3; public final static int FOUR = 4; ....
(jk)