
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@dezide.com> 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