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 collections.sf.net
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 collections.sf.net 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 collections.sf.net 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
collections15.sf.net, where all of the code has been fully generified,
rather than just the API. This isn't a particular criticism of
collections.sf.net - 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 collections15.sf.net, 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 collections.sf.net, 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 collections.sf.net 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 collections.sf.net 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 collections15.sf.net, 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
collections.sf.net 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 collections.sf.net 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: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]