tag:blogger.com,1999:blog-8656465666508353224.post8033409222822732788..comments2023-05-26T04:21:31.288-07:00Comments on Mutability Detector Blog: Immutability and subclassing: are they mutually exclusive?Graham Allanhttp://www.blogger.com/profile/16539618370362116733noreply@blogger.comBlogger15125tag:blogger.com,1999:blog-8656465666508353224.post-14784762964264510902012-10-21T13:03:57.432-07:002012-10-21T13:03:57.432-07:00Just to be pedantic, your MutableMischief is also ...Just to be pedantic, your MutableMischief is also immutable :)<br /><br />Although the return value of getLabel() is different from its superclass, it will always be the same for an instance of MutableMischief, just like a final field would be. To show what I mean, consider MutableMischief to be like this:<br /><br />public class MutableMischief extends Immutable {<br /><br /> @Override<br /> public String getLabel() {<br /> return "Return value keeps changing: " + (System.currentTimeMillis() % 10);<br /> }<br /><br /> public static void main(String args[]){<br /> MutableMischief mutObj= new MutableMischief();<br /> ImmutableClient immutClient= new ImmutableClient(mutObj);<br /> System.out.println(immutClient.printImmutableLabel());<br /> Thread.sleep(1000);<br /> System.out.println(immutClient.printImmutableLabel());<br /> }<br />}<br /><br />One of the times I ran this I got the result:<br /> Return value keeps changing: 6<br /> Return value keeps changing: 8<br /><br />So the issue is *not* that MutableMischief returns a different value than its superclass. It's that, on different invocations of the same method of the same instance of MutableMischief, different results are returned. It just so happens that having subclasses is a way to introduce that behaviour.<br /><br />Is that any clearer?<br /><br />Kind regards,<br />Graham<br /><br /><br />Graham Allanhttps://www.blogger.com/profile/16539618370362116733noreply@blogger.comtag:blogger.com,1999:blog-8656465666508353224.post-57562648774662928112012-10-13T00:00:58.909-07:002012-10-13T00:00:58.909-07:00OK, I think this could be something like this:
cl...OK, I think this could be something like this:<br /><br />class Immutable{<br />private String label="Original Label";<br />public String <b>getLabel()</b>{<br />return label;<br />}<br />}<br /><br />public class MutableMischief extends Immutable{<br /><br />@Override<br />public String <b>getLabel()</b>{<br />return "Not Original Label";<br />}<br /><br />public static void main(String args[]){<br /><br />MutableMischief mutObj= new MutableMischief();<br />ImmutableClient immutClient= new ImmutableClient(mutObj);<br />System.out.println(<b>immutClient.printImmutableLabel()</b>);<br />}<br />}<br /><br /><br />class ImmutableClient{<br /><br />Immutable immutObj;<br /><br />ImmutableClient(Immutable immut){<br />this.immutObj=immut;<br />}<br /><br />public String printImmutableLabel(){<br />return <b>immutObj.getLabel();</b><br />}<br /><br />}<br /><br />The above program should print Original Label But it will print <b>Not Original Label</b>.<br /><br />Thanks...<br /><br /><a href="http://java-journal.blogspot.in/2012/06/string-pool-is-possible-due-to-string.html" rel="nofollow">String Pool is possible due to String Immutability </a>Rajinderhttps://www.blogger.com/profile/07874702857035374398noreply@blogger.comtag:blogger.com,1999:blog-8656465666508353224.post-56126832370389204182012-10-12T16:07:48.695-07:002012-10-12T16:07:48.695-07:00Hi Rajinder,
Good catch. The subclass could use a...Hi Rajinder,<br /><br />Good catch. The subclass could use any field as the return value for getField(). It could either redeclare the field label, or introduce a new one, or return a random string. <br /><br />The point still stands that, because of subclassing, getField() could return different result on different calls.<br /><br />Make sense?<br /><br />Regards,<br />Graham Graham Allanhttps://www.blogger.com/profile/16539618370362116733noreply@blogger.comtag:blogger.com,1999:blog-8656465666508353224.post-81988633259371667222012-10-12T08:01:08.651-07:002012-10-12T08:01:08.651-07:00private String label; in IAmImmutable class has p...private String label; in IAmImmutable class has private access. How can u change its value in sublcass by setLabel() method? It will give error:<br /><br />"label has private access in IAmImmutable".<br /><br />Thanks...Rajinderhttps://www.blogger.com/profile/07874702857035374398noreply@blogger.comtag:blogger.com,1999:blog-8656465666508353224.post-60049931930055933342011-07-09T02:30:03.789-07:002011-07-09T02:30:03.789-07:00That's something I've been thinking about,...That's something I've been thinking about, and a mechanism for tailoring the output of assert has been in place since 0.6. The default assert will be the most strict and the user will be able to supply suppressions. For example, for java.lang.String, you could write something like:<br /><br />assertInstancesOf(String.class, areImmutable(), allowing(field("hash").toBeReassigned());<br /><br />(don't quote me on the syntax, hopefully you get the idea)<br /><br />Something similar could be used for effectively immutable objects. The overall codebase would then have to be assessed manually, to check that publication was safe, but hopefully that would still be a helpful utility.<br /><br />Thanks Craig.Graham Allanhttps://www.blogger.com/profile/16539618370362116733noreply@blogger.comtag:blogger.com,1999:blog-8656465666508353224.post-8700048189769880792011-07-08T14:58:03.671-07:002011-07-08T14:58:03.671-07:00That's exactly what I meant. A unit test could...That's exactly what I meant. A unit test could unsafely publish IAmImmutable and another thread could observe a null field.<br /><br />I didn't remember the term "effectively immutable" from JCIP. Discovering effectively immutable objects seems interesting, and difficult.<br /><br />I recommend splitting the API into assertEffectivelyImmutable() and assertImmutable(). JCIP says "Immutable objects, on the other hand, can be safely accessed even when synchronization is not used to publish the object reference." I think that assertImmutable() should be strict on that point.Craighttps://www.blogger.com/profile/15806804843602653454noreply@blogger.comtag:blogger.com,1999:blog-8656465666508353224.post-3361870368191123892011-07-08T13:25:02.114-07:002011-07-08T13:25:02.114-07:00I'm not sure if I'm interpreting you corre...I'm not sure if I'm interpreting you correctly, but you're right, "Can't be extended" is definitely not the only rule. Classes which cannot be extended can be mutable. Yep, there's much more to it.<br /><br />In my example, I probably should have made the same distinction between Immutable and Effectively Immutable, as JCIP also does. In my example, IAmImmutable is the latter: once an instance of that class is safely published, it cannot be seen to change by clients of the class. <br /><br />However, if it is unsafely published to other threads, the lack of the final modifier would become an issue, as the field could be accessed before it has been assigned. Thus a client of the class could observe getLabel() returning null on the first call, then returning a non-null String on the second call. Safely publishing prevents this.<br /><br />At least, that's my understanding. If you could share a unit test or some other piece of code that demonstrates what you mean, I'd love to see it.Graham Allanhttps://www.blogger.com/profile/16539618370362116733noreply@blogger.comtag:blogger.com,1999:blog-8656465666508353224.post-9991932792077196692011-07-08T13:09:34.712-07:002011-07-08T13:09:34.712-07:00Craig, I'll answer your first question too, th...Craig, I'll answer your first question too, then take another comment to answer your second points.<br /><br />Effective Java includes as one of its five rules for immutability "Ensure that the class can't be extended."<br /><br />See <a href="http://books.google.com/books?id=ka2VUBqHiWkC&pg=PA73&dq=%22ensure+that+the+class+can%27t+be+extended%22&hl=en&ei=32MXTojcJtGn8QOGjZER&sa=X&oi=book_result&ct=result&resnum=1&ved=0CCoQ6AEwAA#v=onepage&q=%22ensure%20that%20the%20class%20can%27t%20be%20extended%22&f=false" rel="nofollow">here (Google Books)</a>Graham Allanhttps://www.blogger.com/profile/16539618370362116733noreply@blogger.comtag:blogger.com,1999:blog-8656465666508353224.post-73807523238873960412011-07-08T06:39:27.502-07:002011-07-08T06:39:27.502-07:00I'll go ahead an answer my own question. Effec...I'll go ahead an answer my own question. Effective Java does not say that an object is only immutable if it can't be extended, because that's not true. The requirements for immutability are quite precise and listed in Java Concurrency in Practice. According to the rules, IAmImmutable is NOT immutable because its field is non-final. If its field were final, it would be irrelevant if its subclasses were mutable, it would still be immutable no matter what. Even without writing a subclass or using crazy reflection, I can write a unit test which proves that IAmImmutable is in fact mutable.Craighttps://www.blogger.com/profile/15806804843602653454noreply@blogger.comtag:blogger.com,1999:blog-8656465666508353224.post-37567881153260934502011-07-07T22:39:12.023-07:002011-07-07T22:39:12.023-07:00Where in Effective Java does it say that an object...Where in Effective Java does it say that an object is only immutable if it can't be extended?Craighttps://www.blogger.com/profile/15806804843602653454noreply@blogger.comtag:blogger.com,1999:blog-8656465666508353224.post-66228209376095184672010-07-14T13:27:42.095-07:002010-07-14T13:27:42.095-07:00I took a look back at the content of this post, an...I took a look back at the content of this post, and saw how some of the wording was completely misleading. Perhaps you wouldn't mind taking a look at the last couple of paragraphs and telling me if the edit makes my point any clearer?Graham Allanhttps://www.blogger.com/profile/16539618370362116733noreply@blogger.comtag:blogger.com,1999:blog-8656465666508353224.post-18778393089843185692010-07-12T15:11:50.291-07:002010-07-12T15:11:50.291-07:00> If IAmImmutable were truly, reliably immutabl...> If IAmImmutable were truly, reliably immutable, you would be happy consuming any of its children (now that’s an evil phrase). But as it is, we have no guarantee that any object under the guise of IAmImmutable is immutable.<br /><br /><br />Herein lies the point I was chipping away at. You *wouldn't* be happy consuming IAmImmutable's children*. There *is no* guarantee that a reference to an IAmImmutable instance is immutable. If you had a constructor which assigned an IAmImmutable instance to one of it's fields, it can be made mutable, the same as if the class received an instance of an interface or abstract class. Until subclassing IAmImmutable is prevented, there can be no guarantee that when you receive a reference to one, it will point to a truly, reliably immutable object. <br /><br />BUT... Mutability Detector is aware of this, and complains when consumers depend upon a property of a class which can't be guaranteed. The reasons you want IAmImmutable to be exposed as mutable fall under the conditions that I tried to describe: when instances are being consumed, and the consumers depend upon their immutability.<br /><br />Without users to gather data from, it's essentially an unknown how much the distinction will matter in practice. What we've been discussing is, I expect, an edge case, where the significance of the distinction is the demotion of a particular case being definitely not immutable, to a warning about a gotcha that may or may not matter. Where consuming classes previously failed, they still fail. Given the examples in the blog, IAmImmutable has went from not immutable to a warning; ComposedOfImmutables has remained definitely not immutable.<br /><br />In regard to the toggle, what I envisage being the real use for this tool is for making assertions in unit tests (a blog entry on this, when the functionality is nearing completion, will follow). Rather than a toggle, or option for the tool, I intend to make the hypothetical Assert.isImmutable() method flexible enough to allow users to overrule the tool's decision, in the inevitable event that the tool generates a false positive. Since one of my favourite features of FindBugs is how it explains its decisions in detail, I'd rather put information in front of the user and let them judge, rather than swallowing warnings silently. Not filling the gap that allows IAmImmutable to be subclasses would fall under this - the user would be alerted, but they could suppress the warning.<br /><br />However, though I still stand by what I've wrote at this moment in time, if I'm proved to be wrong, rest assured the plight of immutability will not suffer under the yoke of my stubborness. For born am I with the humility to admit mistake, which I can effortlessly achieve while simultaneously writing in the tone of a first class twat. <br /><br />* "No I don't want to eat babies! I don't have the time... they're not delicious." - Kyle Cease, anyone?Graham Allanhttps://www.blogger.com/profile/16539618370362116733noreply@blogger.comtag:blogger.com,1999:blog-8656465666508353224.post-1263525933396670122010-07-11T03:46:59.774-07:002010-07-11T03:46:59.774-07:00Here’s my problem with that argument – IAmImmutabl...Here’s my problem with that argument – IAmImmutable doesn’t expose any means of exterior modification of its state after construction. But one of its subclasses – ImInUrClassRuininUrImmutability – can clearly provide paths to modify information defined in IAmImmutable. Although I understand that the mutable *instance* is of a subclass, we’re still allowing a state which is defined in the base class to be changed. If IAmImmutable were truly, reliably immutable, you would be happy consuming any of its children (now that’s an evil phrase). But as it is, we have no guarantee that any object under the guise of IAmImmutable is immutable.<br /><br />> If IAmImmutable was found to be mutable because it wasn't declared final, I could see it putting people off using the tool.<br /><br />I’m all for pragmatism, but if people are creating classes which can be subclassed and modified, then I think they should be told that there’s no guarantee that objects declared as IAmImmutable will be their namesake. And I’d always thought that immutability was something which by definition had to have a guarantee.<br /> <br />Talking in practical terms, you could always provide an option for developers to toggle “Treat non-final classes as mutable”... though I think that’s a weak compromise.Seb Charrothttps://www.blogger.com/profile/05768007406550233763noreply@blogger.comtag:blogger.com,1999:blog-8656465666508353224.post-29604501814446132192010-07-10T16:24:42.997-07:002010-07-10T16:24:42.997-07:00First off, thanks for your comments: frist psot!
...First off, thanks for your comments: frist psot!<br /><br />You're right that it's the danger of being mutated which is important. Generally in developing immutable classes, defensiveness is the key. This is why I've said that the likes of public non-final fields (which can be reassigned after construction) or setter methods (which also reassign fields after construction) are both definitely not immutable.<br /><br />In the example in the blog entry, the distinction isn't between being mutable and danger of being mutable, it's between the use of a class by its clients and the class itself.<br /><br />The specific, concrete class IAmImmutable, is not in danger of being mutated. No matter what you do, if you construct an instance of it directly, from it's concrete constructor, it cannot be changed*. So IAmImmutable is found to be immutable when looked at in isolation, the tool issuing what is essentially only a warning. You're slightly off in your statement "class X is in danger of being mutable" (assuming you meant IAmImmutable) in that the *class* isn't in danger of being mutable. What's more accurate is that "classes which extend X can render runtime instances referenced as type X to be mutable" (bit of a mouthful I know, but the difference is significant).<br /><br />The class not being declared final only becomes significant when instances are being consumed. As in the example, if a class accepts an instance of IAmImmutable, it also accepts any mutable subclasses. At this point, something is in danger of being mutable, but what? Is it IAmImmutable, whose instances *are* immutable, or clients which depend on the instances it receives being immutable, but don't guarantee that those instances are definitely immutable? For me, it's clearly the latter.<br /><br />The distinction wouldn't be that important, and the solution is the same nevertheless (declaring it final), if it wasn't for the devastating effect false positives can have on static analysis tools. If IAmImmutable was found to be mutable because it wasn't declared final, I could see it putting people off using the tool. In my experience with analysis tools, I've found it's easy to be more strict, but much more difficult to be realistic in terms of what the tool demands from developers.<br /><br />Getting back to the example, IAmImmutable introduces mutability, but not in 100% of cases. Detecting the percentage of cases where it does matter reduces false positives and increases effectiveness of the tool (in theory).<br /><br />Hope this clarifies my point, and if you're still in doubt, feel free to question me till I do convince ya :-)<br /><br />~ Graham <br /><br />* actively ignoring the capabilities of reflection, and other such (I don't want to say 'nasty', but yeah) stuff.Graham Allanhttps://www.blogger.com/profile/16539618370362116733noreply@blogger.comtag:blogger.com,1999:blog-8656465666508353224.post-76635825695838294022010-07-10T15:34:03.306-07:002010-07-10T15:34:03.306-07:00I'm not sure I agree - isn't immutability ...I'm not sure I agree - isn't immutability by definition "the quality of being incapable of mutation"?<br /><br />A class with a publicly-exposed variable is mutable though it may never be mutated. I.e. the variable may never be assigned from an external source.<br /><br />In the same way, a class which can be extended is mutable - it can be mutated, even if it never will be. This is the very definition of mutability, isn't it? That a consumer has the means to mutate an object? <br /><br />It seems to me that you've drawn a distinction between "class X is mutable" and "class X is in danger of being mutable" when in fact there is no difference. If there's a danger of mutation, then it *is* mutable.<br /><br />Disclaimer: This comment is not meant as an attack but an invitation to hear some robust arguments :)Seb Charrothttps://www.blogger.com/profile/05768007406550233763noreply@blogger.com