commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From John Watkinson <>
Subject Re: Commons-Collections enhanced with Java Generics Support
Date Thu, 26 May 2005 16:55:53 GMT
Hi Chris, you've made excellent points, which I'll address below:

1. The port appears to me to be a direct attempt to take the existing 
collections codebase and generify its API. It's an approach I initially 
took but abandoned after a while when I realised that much of the 
existing codebase was inappropriate for generifying. To clarify this, 
much of the current collections API is not typesafe, and raises problems 
when trying to generify it. For example, the ChainedTransformer class 
has a constructor that accepts a Collection. The javadoc indicates that 
this should be a collection of Transformer instances, and the resulting 
ChainedTransformer's transform method takes the input object and 
transforms it using each Transformer in the chain, returning the result. 
When generifying the class to ChainedTransformer<I, O>, it's not 
possible to use the following constructor

   public ChainedTransformer(List<Transformer<I, O>> transformers)

because it's generally not possible to take the output of each of the 
chained Transformers and pass it into the next Transformer in the chain. 
After much consideration, it was decided that to maintain compile-time 
type safety, the behaviour of ChainedTransformer had to fundamentally 
change. This e-mail is already long enough, so I don't want to elaborate 
any further. The point I wish to make is that the 
project addresses such issues by compromising type safety - it's 
constructor to ChainedTransformer<I, O> is as follows

   public ChainedTransformer(Transformer[] transformers)

In this instance, the difficulties that generification raises have been 
skirted by sacrificing type-safety, and it's an approach that is taken 
throughout the port of collections. I think this is 
an important point to consider, as probably the most important point of 
generics is to provide compile-time type-safety.

There are definitely some collections that don't take very well to 
generics. ChainedTransformer is one of the worst offenders, as it is not 
clear how it should be changed so as to make it support generics. Other 
collections that have problems are MultiMap and the TransforedXXX 
collections. However, there are some good solutions available for those, 
and we are working on them actively.

Our approach was to shoot for supporting generics in the majority of the 
classes. This was because we wanted to begin using the collections in 
1.5 in our own projects immediately, and there was no existing solution 
for us. Those classes that did not lend themselves well to generics were 
either not converted or were only partially converted. This way, the 
software worked right away and was a clear improvement over the 
non-generic collections. We agree that it has some short-comings in the 
partially-/non-converted areas and we look forward to working with 
everybody to resolve those in the best way possible.

It is our philosophy to not be bogged down by the more obscure cases 
(such as ChainedTransformer). Those few classes that just don't make 
sense at all from a generics point of view should perhaps just be 
labelled as such in the documentation.

2. Whilst the public API of the port has been 
generified, the internal implementation is largely untouched. It's still 
the non-generic code that is present in the current  commons-collections 
codebase. From a black-box approach, this isn't especially important 
provided that the implementation honours the documented API. As I've 
mentioned earlier, this isn't the approach I've taken in, where all of the code has been fully generified, 
rather than just the API. This isn't a particular criticism of - Sun's own implementation of ArrayList<E> takes the 
same pragmatic approach - but it's just a difference I wanted to point 
out. I must say, however, that in the process of generifying all of the 
code in, a number of subtle improvements to the 
generified API became apparent that would not have been so had I only 
generified the public API. That this level of attention hasn't been paid 
to the implementation code in, leads me to worry that 
the generification of the API isn't optimal, though I admit that this 
may be because my first stab at generifying the interfaces was not the 
best and so had to be changed a lot as I generified the implementing 
classes and the problems in the API became more apparent.

Yes, we feel that the some of the internal implementations are 
well-converted, but not all. We look forward to improving the use of 
generics in those classes and throughout the source. These refactors are 
important, but will not change the experience for the users of the library.

3. Here's my biggest worry. The unit tests in don't 
appear to have been modified to reflect the generification of the APIs. 
The 100% success rate of the unit tests is therefore misleading, as it's 
more of an indication that the original commons-collections code on 
which the port was based doesn't fail any of its unit 
tests. What's missing in the unit tests is an attempt to exercise the 
generic modifications made to the APIs. Whilst updating the unit tests 
in, a fair number of minor errors where uncovered. 
They were typically problems whereby it became apparent when writing the 
unit tests that the generic arguments of various methods weren't 
sufficiently flexible. I'm worried that since the unit tests in don't exercise the generic modification that have 
been made, the modifications may not have been exercised at all.

On this point, I don't entirely agree. The behavior of a class is the 
same at runtime regardless of whether the user used generics in the 
source code or not. Any errors in our addition of generics to the 
collections will manifest themselves at compile-time, not runtime. Now, 
such issues are important, and we should make sure that each method of 
each collection is defined consistently from a generics point of view. 
However, as the vast majority of collections implement the java.util 
collection interfaces, a lot of the parameterized types are already 
strictly enforced in the overriding methods at compile-time. This 
trickles down to the helper/private methods, and makes things pretty tight.

However, I agree that some test code should be written to ensure that 
generics are properly employed in those places where issues could have 
slipped between the cracks. Just having that code compile will ensure 
that the generics are properly employed.

Incidentally, there were classes that underwent fairly severe 
refactoring in order to support generics externally and internally. 
Probably the best example is AbstractReferenceMap. For such classes, the 
test suite was invaluable in ensuring that the proper behavior was retained.

4. The javadoc in doesn't appear to have been updated 
to reflect the generification of the API.

True, the docs have only been updated to indicate those classes that 
support partial or no type safety under Java 1.5.

Chris, thanks for these points. We agree that there should not be 
duplicated effort on this project, and we look forward to open 
collaboration on this. More work is certainly required to bring those 
straggling non-generic collections in to the fold, but we emphasize an 
approach that retains the full, working funtionality of the collections 
during these early releases. That way, developers can use the package, 
get used to the generic versions of the collections, and provide us with 
valuable feedback.

 John Watkinson

To unsubscribe, e-mail:
For additional commands, e-mail:

View raw message