
The library may indeed have been poorly documented, but I don't see how what you wrote here addresses Scott's statement in any way. You simply cannot count on undocumented behaviors of a library; they are subject to change without notice.
The behaviour WAS documented, as I've stated in a different thread: It's right there at the top of the iterator_range class if the pre 1.35 docs. However, I have to say I don't like what you're doing - I feel like you're trying to prove that what we're doing is actually wrong in some way. We're looking for a solution to real problem. Forget for a second about whether it or it documented. The question is - what can be done?
I doubt I'll find quotes from the source very persuasive, since what you can count on should be determined by the docs.... of course comments in the source are a kind of documentation.
Dave was just demonstrating why the is_singular() function is broken.
at the top of iterator_range we see:
/*! \file Defines the \c iterator_class and related functions. \c iterator_range is a simple wrapper of iterator pair idiom. It provides a rich subset of Container interface. */
This implies to me that range is trying to look and feel like a container - not like an iterator.
I understand that you drew that conclusion, but IMO it's a huge stretch to claim that a concept that doesn't even exist for containers (singularity) should behave in some container-like way for ranges.
Remember that our problem is not with is_singular(), it is with empty(). is_singular() is just an implementatin artifact. The behaviour we care about is whether or not a default constructed iterator_range should be empty(), in line with standard containers. The comment from the source was Dave's example of why it wasn't unreasonable to assume such behaviour.
I agree that singular iterators (as defined in the standard) are undefined when default constructed;
To be precise, they're not undefined. All singular iterators are alike, regardless of how they're produced (default-constructed or otherwise). They have two defined operations: assignment and destruction.
But not all default constucted iterators are singular.
Perhaps. But did the documentation guarantee that it would work?
Yes - please see the old docs or my previous posts.
You're free to define models of Range that have a default-constructed empty state. Requiring all models of Range to behave that way is antithetical to the principles of generic programming.
We certainly agree on this. We're not proposing that we have a single iterator_range class that fits all purposes, again as I've stated in several posts.
but AFAICT the only thing that a Range has in common with a container is that it supplies a begin() and end() that delimit a sequence of elements.
Actually, the similarity is much stronger than that: iterator begin() const; iterator end() const; size_type size() const; bool empty() const; Unfortunately I don't have my standard at hand (it's at work) but IIRC all of the are part of the "Container requirements".
I would find that argument more compelling if there was a "singular" concept that applied to containers, but there isn't.
We don't care about the singular concept. We only care about the default constructed/empty() concept. Tom