`@Immutable` does not recognize safe array handling
The following two examples use defensive cloning on the way in and out.
Example 1
@Immutable
public final class ArbitraryClass {
private final String[] array;
public ArbitraryClass(String[] array) {
this.array = array.clone();
}
public String[] array() {
return this.array.clone();
}
}
Example 2
@Immutable
public record ArbitraryRecord(String[] array) {
public ArbitraryRecord(String[] array) {
this.array = array.clone();
}
public String[] array() {
return this.array.clone();
}
}
I expected both of these to be considered immutable, but get the following error:
[Immutable] type annotated with
@Immutablecould not be proven immutable: 'ArbitraryClass' has field 'array' of type 'java.lang.String[]', arrays are mutable
Am I missing a way these examples aren't actually immutable? Or can @Immutable processing be improved to allow for this?
The check tries to enforce the sort of deep immutability described here. It encourages using types like ImmutableList<String> instead of String[], because they don't require reasoning about whether they can be mutated at runtime, the contract of ImmutableList guarantees it's always going to be immutable.
So I agree those examples are immutable, but they're probably not a pattern that the check is going to recognize.
Another way to phrase that: the check doesn't do any kind of flow analysis to check whether mutable innards are used in a way which leads to outward immutability.
If I really couldn't use an immutable container, I'd add a suppression with a comment: @SuppressWarnings("Immutable") // cloned on the way in and out.
Ok, thanks for the clarification.