To what degree would the JVM (in my case, HotSpot) perform optimizations pertaining to immutable objects? That is, if the JVM determines that some objects are effectively immutable (e.g. either because all of its member fields are declared as final or the instances of its class are never mutated), what are some optimizations that the JVM may perform?
I don't think it's possible for either the Java compiler or the JIT compiler to determine whether a class is immutable. For classes to be immutable, either their members must be immutable (this is a recursive problem) or their members must be deeply copied when accessed from outside. I think determining the latter in general is impossible.
The compiler does perform some optimizations for (effectively) final variables though. I believe it may inline their value, and maybe there are some other optimizations as well.
Stephan van Hulst wrote:. . . optimizations for (effectively) final variables though. I believe it may inline their value, and maybe there are some other optimizations as well.
For a very long time, compile‑time constants have been inlined in the bytecode. You can confirm this by compiling these two classes, and inspecting their bytecode with
javap -c KettleYou won't see any sign of ROOM_TEMPERATURE or BOILING_WATER in the bytecode for Kettle. Only 20 and 100. That causes problems (according to Bloch and Gafter in Java Puzzlers, I think), if you try to alter those constants, which makes me think there is a general design principle:-
Once a [compile-time] constant, always a constant.
That is a misquote of the title of a play from the 1970s.
For some context, I sometimes program in Frege, a Haskell implementation for the JVM, where millions of small immutable objects are made and probably don't last 10 nanoseconds before becoming garbage. I'm curious of the extent of the performance impact in this case, and what the JVM would do about this.
I don't know about Frege (other than the logician), but a Haskell implementation for the JVM sounds amazing, I'll check it out.
There's a difference between immutable classes in Java and immutability in Haskell. This is because Haskell is purely functional, and therefore variables never change after you define their values. Haskell can make assumptions about types that Java can't; these assumptions are used by the language-to-bytecode compiler. The JVM itself can't make any further assumptions.
Assume you have Java like language, except with the addition of an "immutable" keyword. A method that accepts an immutable parameter would not be allowed to call any mutators on the corresponding method argument, and a method that returns an immutable result promises not to leak a mutable reference to the returned object: Such a language would be able to perform a lot of compile-time optimizations that are natural to a language like Haskell. It can only do this if either the programmer or the language is explicit about this. A compiler can not otherwise determine that these optimizations are appropriate.
Is an immutable keyword consistent with the prociples of OO programming, that you can call mutator methods?
In Goetz et al, they suggest various annotations like @ThreadSafe and @Immutable and (I think) @NotThreadSafe, so people know what the classes they are using are like. You could make @Immutable a built‑in annotation like @FunctionalInterface and the compiler could then do any inlining required.
I don't really see why such a keyword would be inconsistent with OO. C++ has the const keyword which when applied to a method parameter, prevents the client from calling methods on it, unless those methods are also declared as const, which in turn are not allowed to call anything that is non-const. While C++ is not the most shining example of an OO language, const correctness is a feature that I sorely miss in Java. However, if I were to design a language, I would make immutability the default, and use keywords such as 'mutable' and 'mutator':
I haven't quite worked out yet how I would designate the difference between a method that requires an immutable object, versus a method that promises not to mutate the object. Perhaps an 'immutable' keyword after all: