Toward const-ness in Java

In many of these discussions, arguments against use of const in Java have centered on perceived weaknesses of const in C++.

Let’s try to imagine how we could make the const keyword useful in Java. Here’s my proposal.

second thoughts. Not to say that the idea won't work, just that it needs more thought than it's given here.
I was thinking only in terms of compiling, but the only way Java has for knowing a method's signature when a class is loaded, is from information stored in the class file. For code that uses const-ness from another class, it will need the const-ness info at class load time, not just at compile time.

I think that, by looking at the strengths and weaknesses of const-ness in C++, we can come up with a better implementation for Java.

The main points:

  1. To methods outside a const object, the object appears to be read-only.
  2. What const-ness means internally for a class is up to the designer.
  3. It should be impossible to override const-ness

What read-only means for a given class is up to the designer of the class. Typically, it means precisely that the data of an instance cannot be modified. However sometimes it’s desirable for an object to maintain an internal cache or counter, etc., that is updated even when a const method is called.

So let’s say that within the code of methods of a const class, any member data not marked const (or for primitive types, final) is modifiable.

That is, it is up to the class to protect its own data.

Note that this is different from C++, where, to modify member data from within a const method, you have to cast away the const-ness.

One objection to const-ness in C++ is that it isn’t hard to cast away const-ness. Let’s just say that const-ness can’t be cast away in Java.

Another is the confusion between logical const-ness and physical const-ness (Dave Harris, comp.lang.java 1995/11/25)

“An object is logically constant if its abstract state does not change. It’s physically constant if the bit-pattern which implements its state does not change.”

unmodifiability in current Java

Consider the two Java API classes, String and StringBuffer. The first models immutable data objects -- once a String is instantiated, its data cannot be altered. There is no API for modifying its data. In contrast, StringBuffer models mutable versions of the same thing: API functions are available for adding, deleting, etc. its data.

A programmer can confidently pass a String as an argument to a function, knowing that the string data will not be altered by the function. This is a very good thing to know. If a programmer passes a StringBuffer to a function, they are asking for the data to be changed. The function's interface, in requiring a StringBuffer argument, is saying "this data is likely to be changed by this function call".

Now, it was thought useful to produce both interfaces for strings. Why not all other objects in the Java API? Because it's a pain in the butt, of course! It would mean two classes with separate interfaces for each kind of object!

Now consider the more recent class Set, which models a generic set of items. It has many methods for adding and removing its data items. Each these methods specifies an Exception, to be thrown by any class that implements Set which should not allow the data to be so altered. This amounts to another approach to controlling access to data ... but it happens at run-time, not at compile time. And it is a pain in the butt to implement. Its such a pain in the butt that the API provides 11 factory class methods for creating run-time unmodifiable sets. And then to make use of this unmodifiability, further exception-handling code has to be written and tested, anywhere the code might attempt to modify the data. This is really awful.

Another option is to always explicitly pass copies of the data around. This requires code to do the copying, and attentiveness on the part of the programmer to always make sure they are passing a copy, not the original object. That is, it is unreliable. (Let alone, terribly inefficient!)

In languages that support control of responsibility for data, every argument of a function makes it quite clear whether the data might be alterd by the function call or not. Classes specify which methods can be called for immutable objects, and which not. In this way, an unintended modification of the data of an object that should not be modified results in a compilation error.

common misconceptions

Some people are heard using the term “security” in discussions of const-ness. If you are one of these people, please get out a book on C++, read what const-ness is about, and try some examples, before proceeding with the present article. FYI, const-ness has nothing to do with security.

Constness is about clarity of responsibility for updating data. It is a contract, by which code assures its user that it won't alter certain data (and conversely, that it might alter other data).

In C++, it is possible for the code to be lying. That would be very bad. But the point is not certainty. The point is to have a contract, that is easy for all parties to understand.

Thus the const-ness of C++ is a logical const-ness. It is common practice for a class to cast away const-ness internally for bookkeeping purposes. The present proposal also will be about a sense of logical const-ness, but at a different level than that of C++.

Let’s say that const-ness is purely syntactic in Java, that it has no meaning at run time. One advantage of this is that it only affects the compiler, not virtual machines. Code compiled by a compiler that recognizes the const modifier could run in an old virtual machine, although the compiler packaged with that old virtual machine does not implement const.

See also: A Comprehensive Theory of Adding 'const' to Java, by David R. Tribble

const keyword

from outside a const object

from inside an object,

const-ness cannot be cast away