34

This is somewhat controversial topic, and I guess there is as many opinions as there are programmers. But for the sake of it, I want to know what are the common practices in business (or in your work places).

In my work place we have a strict coding guidelines. One section of that is dedicated to magic strings/numbers. It states (for C#):

Do not use literal values, either numeric or strings, in your code other than to define symbolic constants. Use the following pattern to define constants:

public class Whatever  
{  
   public static readonly Color PapayaWhip = new Color(0xFFEFD5);  
   public const int MaxNumberOfWheels = 18;  
}

There are exceptions: the values 0, 1 and null can nearly always be used safely. Very often the values 2 and -1 are OK as well. Strings intended for logging or tracing are exempt from this rule. Literals are allowed when their meaning is clear from the context, and not subject to future changes.

mean = (a + b) / 2; // okay  
WaitMilliseconds(waitTimeInSeconds * 1000); // clear enough

An ideal situation would be some official research paper showing effects on readability/maintainability of the code when:

  • Magic numbers/strings are all over the place
  • Magic strings/numbers are replaced by constant declarations reasonably (or in different degrees of coverage) - and please don't shout at me for using "reasonably", I know everyone has different idea what "reasonably" is
  • Magic strings/numbers arereplaced in excess and in places where they wouldn't have to be (see my example below)

I would like to do this to have some scientificaly-based arguments when arguing with one of my collegues, who is going to the point of declaring constants like:

private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;

Another example would be (and this one is in JavaScript):

var someNumericDisplay = new NumericDisplay("#Div_ID_Here");

Do you stick DOM IDs on top of your javascript file if that ID is used only in 1 place?

I have read the following topics:
StackExchange
StackOverflow
Bytes IT Community
There is many more articles, and after reading these some patterns emerge.

So my question is should be using magic strings and numbers in our code? I am specifically looking for expert answers that are backed by references if possible.

3
  • 2
    A magic variable is a variable that holds a meaning that is not reflected by its contents. The integer value '10' reflects the meaning of the number 10, so there is no need to make it a constant. Same goes for space and semicolon. On the other hand if you have a value '%%??%%' and this is some custom delimiter, then that HAS to be placed as a constant because its contents do not reflect the fact that it's a delimiter. Dec 11, 2013 at 14:32
  • 25
    NumberTen = 10 That is pointless as the number 10 will not be redefined. MaxRetryCount = 10 That has a point a we may want to change the max retry count. private const char SemiColon = ';'; Dumb. private const char LineTerminator = ';'; Smart.
    – Mike
    Dec 11, 2013 at 14:50
  • 2
    Actual question is not clear. Dec 11, 2013 at 16:17

4 Answers 4

93

... when arguing with one of my collegues, who is going to the point of declaring constants like:

private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;

The argument you need to be making with your colleague isn't about naming a literal space as Space but his poor choice of name for his constants.

Let's say your code's job is to parse a stream of records which contain fields separated by semicolons (a;b;c) and are themselves separated by spaces (a;b;c d;e;f). If whoever wrote your spec calls you up a month from now and says, "we were mistaken, the fields in the records are separated by pipe symbols (a|b|c d|e|f)," what do you do?

Under the value-as-name scheme your colleague prefers, you'd have to change the value of the literal (SemiColon = '|') and live with code that continues to use SemiColon for something that isn't really a semicolon anymore. That will lead to negative comments in code reviews. To abate that, you could change the name of the literal to PipeSymbol and go through and change every occurrence of SemiColon to PipeSymbol. At that rate you might as well have just used a literal semicolon (';') in the first place, because you'll have to evaluate each use of it individually and you'll be making the same number of changes.

Identifiers for constants need to be descriptive of what the value does, not what the value is, and that's where your colleague has made a left turn into the weeds. In the field-splitting application described above, the semicolon's purpose is a field separator, and the constants should be named accordingly:

private const char FieldSeparator = ';';    // Will become '|' a month from now
private const char RecordSeparator = ' ';
private const int MaxFieldsPerRecord = 10;

This way, when the field separator changes, you change exactly one line of code, the declaration of the constant. Someone looking at the change will see just that one line and will immediately understand that the field separator changed from a semicolon to a pipe symbol. The remainder of the code, which didn't need to change because it was using a constant, remains the same, and the reader doesn't have to dig through it to see what else was done to it.

4
  • 1
    I totally agree. A few decades ago I worked on a project where messages were sent in segments, each using 8 general registers. Someone had declared #define one 1 #define two 2 etc (or whatever the equivalent was in UK Post Office Coral, the then language of choice). Word came from on high that in future the length field would be the number of bytes, not segments, so obviously the code was changed to #define one 8 #define two 16 etc Jul 11, 2016 at 12:45
  • 3
    As silly as names like Semicolon or PipeSymbol seem, changing one to the other using a script will be a lot easier than changing every affected ; to |.
    – Brandin
    Oct 20, 2016 at 7:25
  • What about the case where a given String literal is used many times in a file, but it has no meaning other than its value? For example, if you're testing that you can receive a certain key in a map in 20 difference scenarios, should I define a constant like so?: public static final String MY_KEY_NAME = "MyKeyName" Sep 2, 2017 at 1:34
  • 1
    @JordanMcQueen There's a case to be made for using bare literals if (and only if) each one is used exactly once and not needed anywhere else. If it's something like each scenario being code that processes a different file format, each format should define its own constant (e.g., CSV_RECORD_SEPARATOR, TSV_RECORD_SEPARATOR, etc.).
    – Blrfl
    Sep 2, 2017 at 2:54
8

Defining semicolon as a constant is redundant, because semicolon is already constant by itself. It is not going to ever change.

It's not like one day somebody will announce "change of terminology, + is the new semicolon now", and your colleague will happily rush just to update the constant (they laughed at me - look at them now).

There's also a matter of consistency. I guarantee that his NumberTen constant will NOT be used by everyone (most coders are not out of their mind), so it won't serve whatever purpose it was expected to anyway. When the apocalypse comes and "ten" gets globally rescaled to 9, updating the constant will NOT do the trick, because it will still leave you with a heap of literal 10s in your code, so now the system becomes totally unpredictable even within the scope of a revolutionary assumption that "ten" means "9".

Storing all settings as consts is something I'd have second thoughts about, too. One should not do this lightly.

What examples of this type of use have we gathered so far? Line terminator... max retry count... max number of wheels... are we positive these will never change?

The cost is that changing default settings requires recompiling an application, and in some cases, even its dependencies (as numeric const values may get hard-coded during compilation).

There's also the testing and mocking aspect. You defined the connection string as a const, but now oops you can't mock database access (establish a fake connection) in your unit test.

4
  • 4
    "It is not going to ever change." I used to think that about the apostrophe (forever tied to ASCII value 39). Some old apps used to curl the apostrophe. But now modern apps treat that ASCII value as a straight apostrophe compatible with old apps, and instead people often use (left single quote, Unicode 8217) for apps compatible with showing a different glyph for the curled mark. Being that Europe uses commas the way Americans use periods as a decimal point, I find myself a tad bit hesitant to declare "not ... ever".
    – TOOGAM
    Jul 12, 2016 at 2:56
  • @TOOGAM well, your example justifies having a DecimalPoint constant - but not Comma or Period constants. It's quite a difference: the former denotes a function, a role or a purpose of the value. "Semicolon" or "comma" don't fall under that category. Aug 11, 2016 at 12:29
  • That's true for the Decimal Point example. However, the apostrophe example does seem to be a similar (or identical) category as a comma (or semi-colon).
    – TOOGAM
    Aug 12, 2016 at 4:06
  • @KonradMorawski Semicolon could be used for many purposes, such as splitting the string or ending the line. It is the meaning of it (not value) that should be used for naming constance. Consider the future change, i.e tomorrow we allow 20 records to process, so constance named as NumberTen is out of context, while maxRecord would be still fine.
    – MaxZoom
    Dec 15, 2017 at 19:31
5
private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;

So your colleague is aiming for a Daily WTF entry. Those definitions are silly and redundant. However, as has been pointed out by others, the following definitions would not be silly or redundant:

private const char StatementTerminator = ';';
private const char Delimiter = ' ';
private const int  BalanceInquiryCode = 10;

"Magic" numbers and strings are constants that have meaning beyond their immediate, literal value. If the constant 10 has meaning beyond "ten things" (say as a code for a specific operation or error condition), that's when it becomes "magic" and should be replaced by a symbolic constant that describes that abstract meaning.

Beyond clearly describing intent, symbolic constants also save you some headaches when you misspell a literal. A simple transposition from "CVS" to "CSV" in one line of code got all the way through unit testing and QA and made it into production, where it caused a particular operation to fail. Yes, obviously the unit and QA tests were incomplete and that's it's own problem, but using a symbolic constant would have avoided that bit of heartburn altogether.

3

There shouldn't be anything controversial about it. The point is not about wether to use magic numbers or not, the point is to have readable code.
Consider the difference between: if(request.StatusCode == 1) and if(request.HasSucceeded). In this case, I would argue the latter is far more readable, but that doesn't mean you can't ever have code like int MaxNumberOfWheels = 18.

P.S.: This is why I absolutely hate coding guidelines. Developers should be mature enough to be capable of making judgement calls like this; they shouldn't leave it to a piece of text formed by god knows who.

7
  • 13
    Drivers should be mature enough to be capable of making judgement on which side of the road they drive ;) Dec 11, 2013 at 14:41
  • 2
    The result of a judgement call can vary even between mature developers, so even arbitrary coding guidelines are meant to improve readability through consistency. This is unrelated to the fact that creating a constant NumberTen makes no sense. Dec 11, 2013 at 14:57
  • 1
    I wouldn't insist that they have to be formal, stamped etc., they can be informal but they should be agreed upon, and this already goes beyond just using one's individual maturity of judgement. But you deleted your comment now Stefan :) Dec 11, 2013 at 15:01
  • 1
    @StefanBilliet - not at all. My point is that readability is improved through consistency. The problem here is not the coding guideline itself, but a guideline taken to extremes through misunderstanding. Dec 11, 2013 at 15:02
  • @MikePartridge Maybe I should have elaborated; the coding guidelines I've seen are more in the trend of a general rulebook on how someone somewhere thought that software should be written, rather than agreements like you and Konrad are probably thinking of :-) Dec 11, 2013 at 15:11

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