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.

Reply via email to