Boost logo

Boost :

From: Richard Peters (r.a.peters_at_[hidden])
Date: 2004-11-10 03:31:41

"Robert Ramey" <ramey_at_[hidden]> wrote in message
> "Thorsten Ottosen" <nesotto_at_[hidden]> wrote in message
> news:cmrk1g$f70$
> > Here's my general take on it: iterators are important and useful as the
> > lower-level
> > infrastructure. iterators are, however, not too user-friendly; the
> > user-friendly interface
> > can be build on top so easy task becomes , well, easy. and that is the
> purpose
> > of ranges and johns range library.
> > without a good iterator library underneith ranges where hard to craft,
> now
> > that we have a good iterator library, we should persue
> > higher abstractions
> I agree that iterators aren't that easy or intuitive to work with. So our
> motivations have much in common. My view is that iterators can be made
> easier to work with without changing their fundamental character and
> the need to introduce what I see as a new concept (ranges) that is "almost
> the same" as an existing concept - pair of iterators.
> Robert Ramey

While iterators are very good at what they do -- provide access to elements
in a sequence -- they do not capture the concept of a sequence very well. If
I want to access a sequence of elements, I'd like to see a clean front-end,
and I believe that John's range library can provide me with such a clean
front-end. Using for_each(s.begin(), s.end(), ...) is too low-level, it
exposes details of a sequence that I do not want to know. I do not want to
for_each on a begin and an end, I want to for_each on a sequence:
for_each(s, ...). It's a conceptual layer, admittedly a small one, but it
provides a great front-end for the back-end of iterators.

std::pair<iterator, iterator> fails at creating a decent front-end. For one
thing, the iterator type must by typed twice. This adds quite some text.
Secondly, it stays in the 'begin-end' concept, instead of advancing to a
real range, of which you can extract an element and advance to the next by
shrinking the range.

You said before that the STL had a very good reason to use iterators. I
agree there, iterators are very effective at what they do, but I'd like a
higher-level interface built on top of that.

For me, the following example from the Range Adaptors and Composition(s)
documentation illustrates that:

    // [1] print all even elements (not using range adaptors)
    typedef boost::filter_iterator<array> filter_iterator;
    rng::for_each( irange<filter_iterator>(
        filter_iterator(some_array.begin(), is_even),
        filter_iterator( some_array.end(), is_even), print );

    // [2] print all even elements (using range adaptors)
    rng::for_each( filtered(some_array, is_even), print);

[1], while already using ranges, is easily rewritten to an iterator-only
version. In [1], two iterators have to be wrapped with a filter_iterator
constructor, both containing the same predicate. In [2], a range adaptor is
used, and the predicate need only be given once. When I read the second
version aloud, I hear exactly what I want to hear: "Take the elements of
some_array, filter out the even elements, and print them". With [1], it's
much more difficult to read it aloud. It also contains redundancy: is_even
is passed twice. While possibly even error-prone, I think this is just ugly.
It's not filter_iterator's fault, the filter_iterator is great at what it
does, but it is the range adaptor that wraps it up nicely and provides a
clean interface to ranges, not just begin-end pairs.

best regards,

Richard Peters

Boost list run by bdawes at, gregod at, cpdaniel at, john at