Constants – Can a Constant Value Change Over Time?

constconstants

During development phase, there are certain variables which need to be the fixed in the same run, but may need be modified over time. For example a boolean to signal debug mode, so we do things in the program we normally wouldn't.

Is it bad style to contain these values in a constant, i.e. final static int CONSTANT = 0 in Java? I know that a constant stays the same during run time, but is it also supposed to be the same during the whole development, except for unplanned changes, of course?

I searched for similar questions, but did not find anything that matched mine exactly.

Best Answer

In Java, static final constants can be copied, by the compiler, as their values, into code which uses them. As a result of this, if you release a new version of your code, and there is some downstream dependency that has used the constant, the constant in that code will not be updated unless the downstream code is recompiled. This can be a problem if they then make use of that constant with code that expects the new value, as even though the source code is right, the binary code isn't.

This is a wart in the design of Java, since it's one of very few cases (maybe the only case) where source compatibility and binary compatibility aren't the same. Except for this case, you can swap out a dependency with a new API-compatible version without users of the dependency having to recompile. Obviously this is extremely important given the way in which Java dependencies are generally managed.

Making matters worse is that the code will just silently do the wrong thing rather than producing useful errors. If you were to replace a dependency with a version with incompatible class or method definitions, you would get classloader or invocation errors, which at least provide good clues as to what the problem is. Unless you've changed the type of the value, this problem will just appear as mysterious runtime misbehavior.

More annoying is that today's JVMs could easily inline all the constants at runtime without performance penalty (other than the need to load the class defining the constant, which is probably being loaded anyway), unfortunately the semantics of the language date from the days before JITs. And they can't change the language because then code compiled with previous compilers won't be correct. Bugward-compatibility strikes again.

Because of all this some people advise never changing a static final value at all. For libraries which might be distributed widely and updated in unknown ways at unknown times, this is good practice.

In your own code, especially at the top of the dependency hierarchy, you will probably get away with it. But in these cases, consider whether you really need the constant to be public (or protected). If the constant is package-visibility only, it's reasonable, depending on your circumstances and code standards, that the entire package will always be recompiled at once, and the problem then goes away. If the constant is private, you have no problem and can change it whenever you like.

Related Topic