Boost logo

Boost :

Subject: Re: [boost] Breaking existing libraries
From: David Abrahams (dave_at_[hidden])
Date: 2008-12-03 12:43:57


on Mon Nov 24 2008, "Daniel Walker" <daniel.j.walker-AT-gmail.com> wrote:

> On Mon, Nov 24, 2008 at 10:40 AM, Thorsten Ottosen
> <thorsten.ottosen_at_[hidden]> wrote:
>> But the change was far from accidental, and was not only motivated by my
>> wish to break peoples code (ironi), but came about because users of the
>> library had great troubles with the original concepts. We had lengthy
>> discussion here on the list. Eric Niebler initiated some of them because
>> he was trying to use boost.range in Boost.for_each.
>
> Name one trouble that anyone had with the Range concepts that was
> caused by the presence of the empty(r) requirement. The accusation
> doesn't make any sense.

Sure it does. It makes it more tedious and error-prone to create a
conforming range, with no benefit at all AFAICT. Is there some benefit
I'm missing, if we can define a single generic empty algorithm in terms
of Range's begin/end requirements?

Seems to me, requiring empty() in ranges is sort of equivalent to
requiring iterators to support distance.

> How did removing empty(r) fix a bug or implementation or interface
> issue with Boost.For_each? Was there a name conflict?!
>
> I mean, look, even if for some reason you did need a Range concept
> that didn't require empty(r), the solution is not to deny all types
> the ability to model Range concepts that require empty(r).

I can't understand what you're saying. Removing empty(r) from the range
concept doesn't suddenly make all types that support empty(r)
non-ranges.

> If you need an even less specific concept of a Range, define a less
> specific Range concept. Don't artificially collapse the requirements
> of richer concept specifications.

I would agree with you if the collapse was artificial, but it's not,
IMO. It's merely zeroing in on the right concept. I realize, of
course, that others may disagree with me, but I really do think there
exists a Platonic Range concept, and it doesn't require empty().

> By analogy, the fact that the most general iterator is a
> SinglePassIterator doesn't mean that we should remove the additional
> refinements of the ForwardIterator, BidirectionalIterator, and
> RandomAccessIterators. That there is a minimalist Container concept
> definition does not mean that we should remove the refinements that
> give us AssociativeContainers, etc. If you needed a Range concept that
> didn't include empty(r), you should define the new, less refined
> Concept, not destroy the more refined Concepts.

BidirectionalIterator provides additional capabilities not available
with SinglePassIterator. What additional capabilities are provided by
RangeWithEmpty?

>> Although you might be of a different opinion, then it was not without
>> sensible reason to remove empty() from the concepts. The new concepts are
>> much clearer, and let us define empty as boost::empty(r) without imposing
>> additional concept requirements.
>
> Concept requirements are not imposing; they are enabling!

Have you written any iterators by hand lately?

> Without the empty(r) requirement users are not able to test a range
> for emptiness directly in a generic way.

  boost::empty(r)

?

> In other words, if a function's only type requirements is that it
> support the expressions begin(r), end(r) and empty(r), then it should
> require that the type model a concept with these expressions. If the
> Range concept no longer supports these expression, then users can no
> longer write generic functions that require them.

Empty is defined as

      // C++0x syntax
      template <Range R>
      bool empty(R const& x) { return x.begin() == x.end(); }

In other words, you can call it on any Range.

> Removing empty(r) also puts limits on the authors of types modeling
> Range.

I don't see how?

> Say you write a type that models Range where the values in the
> range are held in a database on the other side of the network. Perhaps
> there's a fast way to implement empty(r) if you know something about
> the database and/or network topology. However, if empty(r) is not
> required by the concept then you can't offer this benefit to users who
> writing generic code for any Range based on the definition of the
> Range concept. This issue is just going to become more pronounced as
> concepts play a more prominent role in C++0x.

Copying and comparing iterators is supposed to be efficient. If it
isn't reasonably efficient, you've done something wrong.

-- 
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk