[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: the benefits of immutability
On Monday, August 18, 2003, at 08:29 PM, Dan Sugalski wrote:
> At 4:15 PM -0400 8/18/03, Seth Gordon wrote:
>> On Mon, 2003-08-18 at 08:50, Vadim Nasardinov wrote:
>>>
>>> The problem is not that you can't add methods safely. The problem
>>> is
>>> that it is too easy to add them unsafely One of the String's stated
>>> invariants is its guaranteed immutability. The only way to make
>>> sure
>>> this invariant is *never* violated is to prevent subclassing. Thus,
>>> true immutability also requires finality.
>>
>> Object.equals() has a number of stated invariants, too (e.g.,
>> transitivity), but they're documented, anyone who overloads the method
>> is responsible for following those invariants. Why can't the
>> immutability of String objects be handled the same way?
>
> Because I expect that the Java compilers cheat unmercifully when faced
> with String and StringBuffer objects--since they're final and hence
> non-subclassible, the compiler, and more importantly the optimizer,
> can know *exactly* how they behave and cheat appropriately.
Actually, it's more than that. The short answer is "security". The Java
*libraries* cheat because they know that Strings can never *ever* be
mutated. Remeber, Java is supposed to be a secure language, therefore,
the core libraries have to be sure that user code cannot subvert them.
There are many security-conscious entrypoints into the java APIs which
take a String as an argument (e.g. most of java.io.File,
java.lang.ClassLoader, etc). If the user could subclass String and make
it mutable (against the wishes of the documentation), it could
completely break open all the security promises of Java. Yes, the same
thing can be said of any object passed into a java API method, but
check out the number of places Strings are used in core classes vs.
other types. Also note that many other types that could also cause
security issues (e.g. java.lang.Integer, java.net.URL, java.io.File,
more) are also final.
If you wanted an overridable String class, most core java API
entrypoints would need to clone off a guaranteed real java.lang.String
from the user supplied subclass-of-String before doing anything at all
with it. I suspect this would be a large performance hit as well as
introducing a huge number of possibilities for error on the part of the
Java API implementors. If they didn't do this properly, the user
provided string could pretend to be one string during the security
check and then mutate itself to be some evil value after the security
check has passed.
With regards to your example of Object.equals, the reason it's okay for
that to be under user control is the existence of the "==" primitive
which is guaranteed to check object identity. Anything in the java core
library that is security conscious and dealing with user-created
classes will ignore the existence of .equals(), and use ==.
Now, you might argue that the security comes at too great a price, but,
the ability to run untrusted code on your machine without risking the
entire machine is one of the central philosophies of Java and not
something you can brush aside lightly. In a less secure language, it
would probably be considered just fine to have a non-final String.
After all, if the programmer breaks the documented unenforced
restrictions and by doing so causes the program to blow up and erase
itself or some other very odd behavior, "don't do that then" is
perfectly acceptable.
James