Boost logo

Boost :

From: Vesa Karvonen (vesa.karvonen_at_[hidden])
Date: 2001-07-25 15:53:50

From: "Fernando Cacciola" <fcacciola_at_[hidden]>
> From: Jeremy Siek <jsiek_at_[hidden]>
> I am not sure if a *standarized* container-like interface will have a good
> impact on a program design.

I'm not so sure. Functional languages do quite well without iterators. Take a
look at functions such as 'foldr', 'map', 'filter', 'take', 'drop', 'rev',...
that you can find in most functional languages (in some functional languages
they may be named differently).

> The range interface is a *very* powerful abstraction, much much better than
> the abstraction of an (encapsulated) container.

You almost always need both abstractions. Iterators are really a supporting
abstraction, that separates enumeration/traversal from containment.

In fact, you don't need a "range interface", which I assume means a pair of
iterators, to separate enumeration from containment. A single object is
sufficient for describing a range. The reason why C++ uses a pair of iterators
is due to the legacy pointer syntax.

> IMHO, the decision to shortcut from (c.begin(),c.end()) to (c) should be
> done consciously, not as the default practice; otherwise, a program might
> end up stuck in a design that cannot exploit the flexibility of the range
> abstraction.

How? If you can write '(c)', then you can always write '(c.begin(), c.end())'
as long as 'c' is a container. I don't see how support for '(c)' could ever
prevent using '(c.begin(), c.end())'.

As related issue, it is possible to write functions that return an object that
has a container-like interface (has begin() and end()), but refers to the
elements of the container differently. In particular, I'm thinking about the
functions 'drop', 'take' and 'filter' (but there are many more, such as 'rev')
that you can find in many functional languages. I don't see anything that
could not be done with such a container reference, but could be done with a
pair of iterators to a container.

As a related issue, there are often very good reasons for providing an
enumeration interface like this:

    struct not_primarily_a_container
    { struct functor
      { virtual void operator()(element_param_type) = 0;
        // ...

      virtual void for_each(functor& ) = 0;
      // ...

instead of an STL-style iteration interface. The choice between
active/external and passive/internal iteration should be a conscious decision.
However, remember that at least I'm not advocating passive/internal iteration
for generic C++ containers.

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