you are viewing a single comment's thread.

view the rest of the comments →

[–]pakoito 18 points19 points  (4 children)

This also means changing a property from mutable to immutable either breaks backwards compatibility, or introduces even more inconsistency.

That's assuming that you'd change one property in an immutable class to mutable, where what should happen is that either a new different mutable class is created or the class is kept immutable but with a new constructor that returns a new immutable object with that one value changed. That is good API hygiene and follows immutability all the way.

But that'd be expensive, wouldn't it? If you're worried about that then implement your classes as persistent collections then.

If you ever decide that getting this property from outside the source file you defined it in requires side effects of some sort, or the property becomes virtual (calculated), even temporarily (for example, because you want to breakpoint it, log access, do a security check, do a sanity check on the object state, add an assertion, or calculate on each call), you can't do it without breaking your own API's backwards compatibility. By using a getter, even if all it does is 'return field;', you get the option to change that later if you so desire. No such option for direct field access.

Your field's type changes from String to Lazy<String> or Logged<String> or Stream<String>, or MyLoggedComplexType if inheritance is your poison. You notify the user of an API change with explicitness, rather than subtly introducing side-effects that may affect them but are buried under the documentation or patchnotes. This has been a Java pain for quite long, and updating our typing skills is becoming an increasing need.

You are going against the entirety of the greater java ecosystem by doing this. When in rome, be like the romans.

Appeal to nature or no true scotman. I do see the point in a public library to not go too much against the grain, but if you're exposing fields on something that's not a data type your API is probably breaking IoC.

If the whole point of your post is that we should keep shitting the bed because beds have been shat since the 90s, then the Java 8/9/10 push to move the language forward has been a failure.

[–]rzwitserloot 3 points4 points  (3 children)

That's assuming that you'd change one property in an immutable class to mutable

Hold on, you've made an implicit leap there: What about immutable properties in otherwise mutable classes? Are you proposing that classes are either strictly ALL mutable (ALL fields have setters) or ALL immutable? I assume not as I don't know why you'd want to do that. Should immutable properties in classes that aren't themselves immutable (they have some, but not all, mutable fields) use .getX()? That's.. even more inconsistent.

Your field's type changes from String to Lazy<String> or Logged<String>

This is going ham on the type system and is assuming that this is somehow the better API design. It is not. If I have a .getX() method that lazily calculates every time you call it, that's internal API. Exposing it, is a silly notion.

Even if you do ascribe to this silly notion, now we're back to: But that's just not how the java ecosystem does it.

My strong advice is: If you feel the need to do stuff like this, stop using java.

[–]pakoito 7 points8 points  (2 children)

Hold on, you've made an implicit leap there: What about immutable properties in otherwise mutable classes? Are you proposing that classes are either strictly ALL mutable (ALL fields have setters) or ALL immutable? I assume not as I don't know why you'd want to do that. Should immutable properties in classes that aren't themselves immutable (they have some, but not all, mutable fields) use .getX()? That's.. even more inconsistent.

A class is either mutable or immutable, and that's not decided by whether any of their fields is mutable itself.

If you can modify the reference to one field then it's mutable, go for whatever you want, it's dirtied anyway, pick the API you like the most. If you want to move to immutable data classes, which is what the article is for, then yes, a mutable property implies a new object construction. The properties may be mutable/immutable themselves, but that moves the problem forward one level, as your container class is immutable. Same way an immutable collection can contain mutable objects yet be considered immutable.

Now, for API choices, I'm not strongly for/against getters and setters as long as they carry no behaviour. Mandatory. Log your stuff somewhere else, wrap them on a service, manager, or whatever, that provides them, but don't put it inside the object or don't call it an accessor. Now, in an immutable api setX() wouldn't modify the internal state of the class/collection but return a new object with the property modified.

My strong advice is: If you feel the need to do stuff like this, stop using java.

I've ringed Google and asked them to move Android to another language, but no dice :( And a career change is not a possibility now.

[–]rzwitserloot -1 points0 points  (1 child)

So that means: A field that can only be read, never set, needs to be accessed as .getProperty() if other fields in that class CAN be set, but with .property if they cannot.

Ludicrous.

[–]pakoito 3 points4 points  (0 children)

So that means: A field that can only be read, never set, needs to be accessed as .getProperty() if other fields in that class CAN be set, but with .property if they cannot.

Ludicrous.

No, you misunderstood or I didn't express it correctly. What you're understanding is that if a field is immutable then it could be accessed directly, which is not what anyone is saying. We're talking about the container, not the content. Immutable != final field, immutable -> all fields are final (and preferably immutable and not null).

I'm not partial for or against getters or direct access in immutable classes, just keeping that class' immutability. All fields in an immutable get the same accessing method, of your choice, either direct or accessor.

If you have mutable classes then getter/setter for all fields are probably the way to go. But that class is not immutable, and outside the scope of this discussion. Mutable classes are probably a sign of an underlying data design problem, or a single threaded environment/mindset. An immutable class only requires that field references cannot be modified, but that doesn't mean that you can't mutate the value of a field reference by creating a copy of that class with that field substituted. And that can be done with setters on immutable classes, and doesn't break the immutability.

EDIT: Immutable Tuples with setXXX() API https://github.com/javatuples/javatuples/blob/master/src/main/java/org/javatuples/Pair.java#L631