On 2008-04-03 21:38, (e-mail address removed) wrote:
[...]
James, can you explain what you meant by "... for most everyday jobs
like this, in fact, the Java collections library (and especially the
concept of iterators in Java) is far superior to the STL."?
While it was some time ago since I last used Java (before generics) I've
always liked the way the STL iterators, it is a quite simple concept but
still very powerful. To my knowledge there is not easy way to perform
operations on a subset of a container using Java's iterators.
It's easier with Java's iterators than with those of C++. Try
it sometime: call std::transform with some function which should
only be applied to every third element. In Java, you simply
create a filtering iterator (using an anonymous class, if you
wish). In C++, you use boost::filtering_iterator, of course,
it's still more awkward (since you need to create two of them),
and from a purely STL point of view, you should take a look at
the hoops boost::filtering_iterator has to jump through.
Of course, the real problem comes when you want to call a
function to operate on a subset determined by another function.
In Java, that would simply be f( g( collection ), operation ),
where g( collection ) returns a filtering iterator, and f takes
an iterator (any iterator of the correct type), and the
functional operation object. In C++, g must return a pair of
iterators, and you need to store them somewhere, and then call
f() in a separate statement.
Projection and filtering iterators, and function chaining, are
some of the most fundamental concepts, which I used to use
everywhere, in pre-STL days.
The iterator pattern in the GoF was established and standard
practice as early as 1990. Neither Java nor the STL have the
excuse of not knowing the flaws in their iterator idiom by the
time they were developing them. In the case of Java, they
adopted existing practice (e.g. the USL library) known to be
somewhat flawed (next and accessing the element should be two
separate operations); in the case of the STL, the authors
decided to ignore all existing practice, and invented something
far less usable.
(There are few special cases where the two iterator model is
useful. It works well for tokenizing an input stream, for
example. The problem with this is that every time I've wanted
to tokenize an input stream, I've either had input
iterators---which don't allow establishing a sub-range using a
previously saved iterator---or a random access container, in
which case, I could just as easily use indexes, rather than
iterators. In fact, my ParserSource class is modeled more on
C++'s other iterators, streambuf, than it is on STL iterators.
But it really could be just a GoF iterator as well.)