
on Fri Nov 21 2008, "Scott McMurray" <me22.ca+boost-AT-gmail.com> wrote:
On Fri, Nov 21, 2008 at 17:09, Tomas Puverle <Tomas.Puverle@morganstanley.com> wrote:
1) Empty ranges are useless and they cannot even be reliably tested for emptiness.
No, empty ranges are useful and can be reliably tested.
The empty() function now asserts and the is_singular() function behaves differently between debug and release builds, making it impossible to detect if a range is, in fact, empty.
Yes, singular ranges are almost useless, and cannot be tested for singularity. This seems reasonable, as it's just like ints and iterators. I wouldn't say that a singular range is empty, just as I wouldn't say that an uninitialized int has a value.
That's my inclination, too. Of course, I wouldn't object to another iterator range class that gives the stronger guarantee that it is never singular. There's no point in distinguishing the idea of "singular" from that of "empty" if they are really the same thing, though.
I would agree that is_singular should not be available at all in release builds, if it's never useful there. I'd consider it analagous to iterator debugging features, and would think it might be exposition only.
"Exposition only" in the standard is used to give a sense of how something might be implemented, or to say, "here's a working implementation but we're not saying you actually have to do it that way, so long as you give the right observable behavior." So I don't think "exposition only" is quite the right terminology. Iterator debugging isn't described that way anywhere, AFAIK.
In addition, this is not documented well and can lead to subtle bugs and undefined behaviour, which will only manifest itself in release builds.
But what semantics for empty *are* documented?
http://www.boost.org/doc/libs/1_37_0/libs/range/doc/boost_range.html#Semanti...) returns boost::begin(x) == boost::end(x)
That's undefined when begin and end return singular iterators,
Correct.
so I'm not convinced that the "singular implies empty" behaviour was ever documented. (The "returns" entry for empty is the same for 1_36_0, 1_35_0, 1_34_0, and 1_33_1.)
Hmmm.
2) The behaviour is unintuitive. Range is a generalisation of the interface of the std::containers. With this change, containers and ranges can no longer be used in the same code path.
Why would you ever want to pass a default-constructed range to anything?
I will admit that there have been times that I really wished default-constructed iterators all had a value analogous to NULL, that was different from all other values of the same type and yet nonsingular. But that's not how it is, and if you're going to build a range on top of the existing iterator abstraction, I don't see how you can do much better. -- Dave Abrahams BoostPro Computing http://www.boostpro.com