6

In this 6 year old question top answers say that it is not possible to verify immutability. On the other hand on the bottom there are two quite recent answers which suggest that one can use:

To detect if class is immutable.

My questions are: Are these tools useful in real life? Is there any other (better) solution? Has anything changed during these few last years?

Community
  • 1
  • 1
Marcin Szymczak
  • 11,199
  • 5
  • 55
  • 63
  • possible duplicate of [How do I identify immutable objects in Java](http://stackoverflow.com/questions/203475/how-do-i-identify-immutable-objects-in-java) – durron597 Jan 08 '15 at 16:41
  • 2
    I'm more concerned if the state-of-the-art has changed during last 6 years. I'm aware of that `possible duplicate` thread. – Marcin Szymczak Jan 08 '15 at 16:43
  • It is a pity that none of the most popular languages (no language that I know of, actually) natively supports immutability. That would solve an awful lot of problems. – Mike Nakis Jan 23 '15 at 14:50
  • As we appear to be reaching the limit of clock speeds and we are moving to more and more cores, multi-threading is becoming more and more important. Unfortunately, multi-threading with shared resources is a high art, practiced only by expert programmers, as it is by nature all just 'bugs waiting to happen'. The alternative is share-nothing multi-threading, which relies heavily upon immutability, so we really need tools to guarantee and enforce it. Think of the n00bs! – Mike Nakis Jan 23 '15 at 14:51

2 Answers2

1

While I'm sure there are many tools for directly testing if a class is immutable the real issue is testing immutable classes that allow fields that have an interface or abstract class declaration. Basically only sealed immutable classes can be allowed as child fields since inheritance often breaks immutability.

Its pretty hard to make composite immutable objects with out using the Java Collections API (ie not using Map, List or Set, etc.

The other issue is that just because a field is final doesn't really make it "final". Many serialization tools like Hibernate will happily construct immutable objects and set final fields through reflection.

The only really way I see is of detecting true immutability is through runtime analysis but it may take a long time before your code actually hits a specific use case where the mutability happens and I would imagine this sort of instrumentation to be rather expensive.

Another interesting sort of assumed corollary of immutable objects is that they should not change things outside when they are constructed. That is constructing an immutable object should be side effect free. This is where the tools will have a hard time. You could easily make an immutable object with a constructor that does all sorts of external nastiness like kicking off threads or setting system properties.

Adam Gent
  • 47,843
  • 23
  • 153
  • 203
  • You could use Guavas [Immutable Collections](https://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained) instead. – Tom Jan 08 '15 at 16:52
  • 1
    Yes but those are concrete classes. Basically you can never allow interfaces in your immutable objects. – Adam Gent Jan 08 '15 at 16:54
  • 1
    @Tom also `ImmutableList` is not final so you can easily construct an object that needs `ImmutableList` in its constructor with a naughty `ImmutableList`. Also curious ... what do you think is backing the `ImmutableList`.. I'm guessing a very mutable array. For all we know a bad `ImmutableList` could create a thread in its constructor and randomly change the backing array. – Adam Gent Jan 08 '15 at 17:11
  • I agree with both. Haven't thought about evil subclasses. – Tom Jan 08 '15 at 17:20
  • Disclaimer: I'm the author of Mutability Detector. All your points are spot on, and I've encountered them in the development of Mutability Detector's analysis engine. Assigning an instance of a non-final class causes analysis to fail, but the warning can be suppressed, e.g. if you know better than the tool does that every concrete implementation is immutable. That includes Java collection classes like `List`, `Set`, etc. but the analysis recognises when they are safely copied and wrapped into an unmodifiable version, like so `this.myList = Collections.unmodifiableList(new ArrayList<>(src));` – Grundlefleck Jan 10 '15 at 16:37
  • There's currently an open ticket for adding this support for Guava's immutable collections. It would still require a safe copy into a "known" immutable concrete implementation. I.e. if you don't use a whitelisted constructor/static factory for the immutable collection, it will raise a warning. This is to protect against the evil subclass problem. – Grundlefleck Jan 10 '15 at 16:44
  • w.r.t. Hibernate and other forms of reflection causing mutability, that is a big caveat when declaring that classes are immutable. If you really need that not to happen, you must install a `SecurityManager` that will prevent it. Otherwise someone could change `Integer.valueOf(42)` to return something other than 42. I slightly disagree that *anything* can detect "true" immutability on the JVM, even runtime analysis. I took the approach of aiming for a very high level of confidence, rather than "proving" it to be so... – Grundlefleck Jan 10 '15 at 16:44
  • 1
    Also, as you rightly point out, sometimes it's not only immutability that's interesting, but being "side-effect free". I very much don't try to solve that problem as it's Hard(tm). Particularly on the JVM. To conclude, I believe that Mutability Detector is useful, even if it's can't "prove" anything, as it can give greater confidence that e.g. someone hasn't accidentally introduced a setter method. Sorry for the many responses, hopefully they're found to be useful, and not spammy :) – Grundlefleck Jan 10 '15 at 16:53
0

Regarding whether a tool is useful in real life, it depends why you need immutability (as that referenced post asks, are you verifying at runtime, or via inspection, or protecting against malicious code, or just ensuring your own code is immutable?). The simplest assurance that a class is immutable if you're manually reviewing it is that all field writes occur only in the constructor or that all fields are final (or both).

But that's still limited because "final Object x" assures that your reference doesn't change but not that the referenced object doesn't change. As Adam eludes to, if that's a list, the underlying list could change, which could cause thread problems in your (otherwise immutable) class. And if you used the value in the list to determine your hash code (you use x.hashCode() as part of generating your own hash code) then your hash code would change violating other rules (so an immutable view of a list isn't even sufficient).

If your immutable class wouldn't be affected by changes to a held object, then it may be OK for your purposes.

Checking at runtime has to be time/depth/scope limited so can't be perfect. Those tools (or any similar runtime approach) have some use, but it really depends on why you need to determine immutability. If you can spec immutability as part of an API requirement, detect violations of that rule (e.g. hashCode of object changes), and throw an exception when they change, then you don't need to detect it yourself. Or trust your callers. If you're trying to write the immutable class, those tools don't help at all. If you're really looking for thread safety, immutability is, unto itself, an insufficient answer.

It's not a satisfying answer to this question (which is a good one), but I think in most cases it ends up being the wrong question to ask if you look at the problem more closely.

user1676075
  • 3,056
  • 1
  • 19
  • 26
  • Have made several comments on the implementation of Mutability Detector that anyone reading may want to refer to. Your concern of having a field of `final Object x` be mutated is entirely correct. That's why Mutability Detector's analysis will raise a warning if any field is not immutable, with caveats. This is of course transitive, the type `Object` could be anything at runtime so it makes the class mutable, but if the field is of type `Foo`, where `Foo` is final and immutable, it doesn't cause a warning when assigned as a field. – Grundlefleck Jan 10 '15 at 17:02
  • I totally agree with "If you're really looking for thread safety, immutability is, unto itself, an insufficient answer." but I disagree with "If you're trying to write the immutable class, those tools don't help at all.". Mutability Detector's analysis is not sound, so it cannot guarantee correctness, but it *can* tell you if you've obviously screwed something up, e.g. accidentally introducing a setter method. That analysis can be run in a unit test automatically, and repeatedly, to catch mistakes cheaply. If you are aiming to introduce immutable objects for thread safety, that does help. – Grundlefleck Jan 10 '15 at 17:05
  • Sorry, I should say "that *can* help", but of course YMMV. I have found it to be helpful, but as the author I'm clearly biased :) – Grundlefleck Jan 10 '15 at 17:07
  • Fair: yes, it could help even with one's own code (my intent was not to diminish the value of said tools). Just if I were writing the class I'd probably take other approaches (such as finality). My inclination is such tools are best when I don't have access to the code (if I have access to the code, and can modify it, then a much larger world of options are available). – user1676075 Jan 10 '15 at 17:28
  • Interesting, which tools would you use if you had access to the code? One of my intentions with Mutability Detector is to allow unit testing your own code for immutability, as you develop it. Another use case is runtime analysis of other people's code, but it's the same static analysis that's performed. – Grundlefleck Jan 10 '15 at 18:49