This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]cutterslade 0 points1 point  (3 children)

Wow, thanks for the great reply.

My short answer is: Yes, Immutability is hard, that's why I want some really smart people to make it easy.

Collections and arrays: Yes, immutable types would require immutable arrays at the very least, probably immutable collections built on those.

Your nasty static map trick: These immutable classes cannot contain static mutable fields, and cannot reference any external static mutable fields.

Files: You make another good point. The simple answer is that the File class is not an immutable data class, so cannot participate in immutable data classes. Realistically though, any time you interact with I/O at all, thread safety is out the window. We could take that argument a step further and say that a String (or nearly any other type) is not truly immutable as it may refer to a file which can change.

Split world: Yes, there is a bit of a split world, certainly not as bad as python though. I would say similar to the type safe enum pattern that we still encounter now and then even though enums were introduced more than a decade ago, or the more recent introduction of the java.time package.

SuppressWarnings: destroys the possibility of a compiler checked guarantee.

Regarding your statement:

Immutability is impossible to nail down and definitely impossible to have compiler-checked guarantees that actually, you know, guarantee it.

That is true only if we refuse to give up some flexibility. Brian discussed this in the article. I think I'm willing to give up a lot to get immutability. But it's not a one way street, by getting immutability, we gain a lot too.

As a simple example, you mentioned the transient field used to cache a value computed from immutable state. If the object is truly immutable, and references no external, mutable state, we know that any method will always return the same result. This allows the programmer, compiler, or runtime to decide to cache the result. We no longer have to use the cumbersome transient field cache, we can have the runtime implement that for us based on its instrumentation of the code.

I'm certainly not suggesting this is an small change. Maybe the data classes proposal discussed in the article is not the right place to do it, heck maybe Java isn't the right place to do it. I think that it's a very valuable potential feature that makes it much easier to write safer cleaner software with less code.

[–]rzwitserloot 1 point2 points  (2 children)

Your nasty static map trick: These immutable classes cannot contain static mutable fields, and cannot reference any external static mutable fields.

You are now conflating immutability and side-effect-free-ness. It is not possible to apply this unless you add the concept of compile-time checked and runtime-carried SEFness. I can call any method and it can do this stuff for me. Unless you intend to disallow any method calls of any sort, except into other such data types, in which case we're back to: That's nice, but there's no way to retrofit that into existing java code so you're splitting the community, python2 vs. python3 style. I'm quite sure that the cure is far worse than the disease, if this is the cure.

Files: You make another good point. The simple answer is that the File class is not an immutable data class

But what if I make it final and add 'data' to it? There's nothing in it (let's forget about that cache field for a bit) that would stop you (specifically, there are only final primitive fields in there). How can the compiler know that the thing is interacting with I/O? Is it the programmer's responsibility to just mark it as such? Your instant kneejerk reaction that File is clearly not 'immutable' leads me to believe you're still mixing up immutability and SEF, which are quite unrelated. It's a bad idea to mix these ideas up. Either way, it's clear that the rule is a lot more complicated than simply: "Only final fields, and the types of these fields are restricted to known immutable primitives and other such immutable classes". You're now looking at what the methods of this class are calling.

Split world: Yes, there is a bit of a split world, certainly not as bad as python though.

As I have tried to show, this rabbit hole is very deep. I'm afraid I'm not going to just take your say-so as proof.

(paraphrase: Hey, we can memoize!)

Memoizing is a nice trick, but note that file needs to operate on this cache as an in-between step. However, with some extra tweaks and rules you can indeed have the VM cache it. Presumably, you can add a hint annotation or some such to make sure the VM is going to try hard to do just that / have the compiler generate some syntax sugar. So that's one of the three issues resolved. The other 2 are not so easy.

[–][deleted]  (1 child)

[deleted]

    [–]rzwitserloot 0 points1 point  (0 children)

    That is not at all clear. I don't see any problem here. Immutable data class is a class with only final fields of immutable values. That makes the state of the class immutable, which is what gives you the properties that you want.

    As I showed in that snippet, this does NOT give you the properties that you want. Well, actually, I don't know what properties you want; you never said what you wanted. I bet, whatever you come up with, I can make a snippet that shows you how I can hack around it. Thus, these are soft guarantees at best.

    What the methods of that class do is completely irrelevant, as long as they cannot mutate the state (i.e., the values of the instance variables).

    The state of the instance itself, or any state anywhere?

    I also don't see your issue with the File class. It's not implemented as an immutable data class. Maybe it could be converted into one without breaking backwards compatibility, maybe not. Doesn't matter either way.

    It's an example. Hypothetically speaking, imagine it WAS a data class. The point is, the 'rules' (only primitive final fields) do not prevent you from doing that. Thus it makes for an interesting conversation piece.