
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. 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). 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. 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.
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! Without the empty(r) requirement users are not able to test a range for emptiness directly in a generic way. 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. Removing empty(r) also puts limits on the authors of types modeling Range. 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.
The library changed after its original form, and into something much better.
How is it better to not be able to check for emptiness in a generic way?
And the change was motivated by real user feedback, something which the original review in some sense could not provide as much of.
I'm sure you had feedback regarding iterator_range. However, I seriously doubt that you received feedback from users demanding that empty(r) be immediately removed from the definition of the Range concept. That doesn't make any sense, Daniel Walker