Functions that return the "exclusive ownership" of newly created mutable objects often need to be the most specific type of practical; those that return immutable objects, especially if they can be split, should often return less specific types.
The reason for the difference is that in the first case, the object will always be able to create a new object of the specified type, and since the recipient will own the object and it will not say what actions the recipient may wish to perform, there will usually be no way for the code returning the object to know whether any alternative implementations of the interface can satisfy the needs of the recipient.
In the latter case, the fact that the object is immutable means that the function can identify an alternative type that can do anything that a more complex type can do, given its exact contents. For example, the Immutable2dMatrix interface can be implemented by the ImmutableArrayBacked2dMatrix and ImmutableDiagonal2dMatrix . A function that should return an Immutable2dMatrix square may decide to return an ImmutableDiagonalMatrix instance if all elements with the main diagonal are zero or ImmutableArrayBackedMatrix if not. The first type will take up much less storage space, but the recipient should not care about the difference between the two.
Returning Immutable2dMatrix rather than a specific ImmutableArrayBackedMatrix allows the code to select a return type based on what the array contains; it also means that if the code that should return the array has a suitable Immutable2dMatrix implementation, it can simply return it, instead of creating a new instance. Both of these factors can be the main “victories” when working with immutable objects.
However, when working with mutable objects, no one plays a role. The fact that the variable array may not have any elements from the main diagonal when creating it does not mean that it will never have such elements. Therefore, although a ImmutableDiagonalMatrix is actually a subtype of a Immutable2dMatrix , a MutableDiagonalMatrix not a subtype of a Mutable2dMatrix , since the latter can accept stores from the main diagonal, while the former cannot. In addition, although immutable objects can often and should be shared, mutable objects cannot at all. The function requested for a new mutable collection initialized with specific content must create a new collection, regardless of whether its support store matches the requested type.
supercat Sep 02 '15 at 18:48 2015-09-02 18:48
source share