Dear Guava Team,
I’d like to argue for letting the guava ImmutableCollection types (ImmutableList, ImmutableGraph, and so on) implement new interfaces, say, ImmList, ImmGraph, and so on, that would reflect their contracts but allow subclassing. I realize that this has been evoked already but have not found detailed discussions about this specific proposal and its strengths (and weaknesses), so I have some hope that this proposal deserves to be argued for.
The proposal
In more details, there would be one Java interface for each Immutable* type. The interface would exhibit the contract of its corresponding Immutable type. For example, there would be an ImmCollection interface (or any other name considered adequate) that would extend
Collection and whose instance methods signature and javadoc would be identical to
ImmutableCollection, an ImmList interface that would extend ImmCollection and
List with instance methods and javadoc identical to the
ImmutableList type, and so on. The existing Immutable* types would be declared to implement those interfaces.
Some counter-arguments
Let me start with the usual counter-arguments that have probably sprung to the mind of the reader. It is usually said, correctly of course, that the fact that the Immutable* types are classes and not interfaces make them non implementable by anyone else than the Guava team. This is sometimes considered a feature, not a problem, as it may help the user trust that the implementations are indeed immutable. Also, it is observed that the Immutable* types actually correspond to several implementations, not just one, and that it is hard to see a reason for someone to want one’s own implementation for at least some of these types. Finally, interfaces also sometimes (when sealed) do not permit own subtyping, so the interdiction of “own subtyping” is not specific to classes. As a result, the Guava team argues that the Immutable* types should effectively be treated as interfaces, not as classes. (Refs:
Colin D,
Louis Wasserman,
Wiki,
Chris Povirk.)
Argument in favor
I do not think that these arguments stand up to scrutiny when considering the specific current proposal. It is true that forbidding anyone else than the Guava team to implement Immutable* types may be trust-building, but isn’t it a bit lacking modesty (no offense intended) about the Guava team? If one agrees with the general advice to API builders to return interfaces rather than types in order to be free from swapping implementation in the future, it also seems reasonable to admit that for Immutable* types, the Guava team could not have come up with the best possible implementations for every possible use cases. Someone could face a very specific situation where a very specific implementation will feature better performances (hints of such situations
here,
here). Also, having interfaces may enable use cases that are extremely difficult to achieve without first convincing the Guava team to change their implementation (see
here). In short: decentralization of decisions, by letting developers provide their own implementations, is usually considered in the object oriented world as outweighting the benefit of having just one organization controlling the implementation of a type, even though it is true that the one-organization-implementing approach gives more guarantees of correctness to the users who trust that organization.
Most importantly, the current proposal still provides the possibility for anyone to use Immutable* types if they want the guarantee of Guava-implementation of the types; it just _adds_ the possibility for an API developer to be not tied to the Guava-implementations for those who value the freedom of swapping implementation.
Let me make it clear that I do _not_ think that there is any reason to mistrust the quality of the implementation of the Guava team: it is clear that this library is of extremely high quality. But still, as a matter of principle and as a practical matter in specific cases, it seems to me to be valuable to let the users of Guava (at least the ones who provide API that they intend to maintain for some time) apply the conventional wisdom of giving their future selves an ability to come up with their own (or any other organisation than Guava) implementation of the types that they commit their API to return.
I hope that this proposal will be given some thoughts and I apologize if it is redundant.