Hi, > I could make a seemingly immutable class (both final and containing only > final fields), which nevertheless quaks, walks, and looks like a > duck^H^H^H^Hmutable, using a private static IdentityHashMap. If I can do > that, then @Immutable as a reliable construct is meaningless. Thus, > @Immutable is useless unless it also implies that all methods in this > immutable class are side effect free.
I think, as long as we're not talking about defining standards, there is still value in best guess attempts. The more weird stuff you do in your intended immutable class, the more you risk getting a false positive from whatever tool you use to verify immutability. As the creator of such a tool, I may be biased in that opinion ;-) Also, there's not necessarily a constraint that such a check would be done by the compiler. It could be a tool such as FindBugs, a run-time checker (hint: using reflection for this would be a Bad Idea), or a unit test (such as my tool allows). > A second major problem is that java classes aren't final by default, and > java has no notion of sealed types (sealed = a scala construct whereby a > type is public, but only other types in the same package as it are allowed > to implement/extend it). Thus, a non-final type cannot usefully be treated > as immutable/SEF, as anyone could make a subclass that trivially breaks > these constraints. Some mechanic to ensure that subtypes do NOT break > their parent's @Immutable annotation would have to be in place. This would > mean that lots of useful seemingly immutable classes that exist today can > not be marked with @Immutable as that would break backwards compatibility. It's a common misconception that a class has to be final to be immutable, as described in Effective Java, it actually just needs to prevent subclassing. In Java, this can be done with a non-final class, but only private constructors. I believe your sealed class semantics could be achieved with the most visible constructor having the default package scope. In some cases that's not even entirely necessary: if your code can be guaranteed to only deal with instances of that exact class (e.g. every instance is new'd up with that class' constructor) then you guarantee no rogue subclasses are involved and your class is still semantically immutable even though it breaks one of 'the rules'. Sometimes that can be verified easily, other times it would be too expensive, but it's an example of the kind of check that is possible with static analysis. > I conclude that @Immutable is still handy but only as a purely documentary > / compiler warning entity. The compiler could help you a bit by telling > you about attempting to defensively copy an @Immutable, and it could > _maybe_ hint that you appear to be causing side effects or mutating fields > in a class which is @Immutable, or has a supertype which is @Immutable. > This would be a slight update to simply documenting that a type is > Immutable. The JVM will definitely not use @Immutable to change its > behaviour; i.e. it will NOT memoize method calls, and it will NOT ignore > synchronize locks when dealing with such objects. I completely agree with that, the language and it's associated edge cases for such a behaviour would probably inspire an entirely new edition of Java Puzzlers :-) > This also neatly sidesteps the issue of caching results, which makes a > class look mutable whilst it should be treated as immutable (even > java.lang.String does this for hash codes, so quite relevant)! Yes, this is... hard. String has what's known as a 'benign data race': when hashCode() is executed by different threads, there is a possibility that the hashCode field is computed and set twice, but since the result depends on only other immutable state, it doesn't matter, since they will always get the same result. While I don't think it's been proved that detecting this is impossible with static analysis, I've pretty much given up on trying to recognise such a pattern from the bytecode alone. Regards, Graham P.S. while I've made reference to a tool I released which is relevant to this discussion, I wasn't sure if it was bad form to promote it here. So I'll wait to see if anyone's interested to hear about it, in which case I'll happily link to it. -- You received this message because you are subscribed to the Google Groups "The Java Posse" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/javaposse?hl=en.
