Boost logo

Boost :

Subject: Re: [boost] Is Boost.Range broken?
From: David Abrahams (dave_at_[hidden])
Date: 2008-11-23 20:46:52


on Sun Nov 23 2008, "Dave Handley" <dave-AT-dah.me.uk> wrote:

> Response inlined - thread snipped where we agree :)
>
> David Abrahams wrote:
>
>>
>> What's your problem with this thread? The problem is certainly getting
>> a lot of attention.
>
> My main issue with this thread is not the attention it received - it's
> the extent to which a discussion about a breaking change to a library
> has turned into a philosophical discussion. Really the discussion
> about what a range is should have taken place at review time for the
> library, now we should just be able to confirm or not that a breaking
> change has happened, and either fix it or not.

I think if you look back at the thread you'll see that you introduced
the first philosophical statements.

>> Sure. The argument I was responding to included statements like,
>>
>> "This implies to me that range is trying to look and feel like a
>> container - not like an iterator."
>>
>> and
>>
>> "...if you think of a range as being more like an iterator than a
>> container, but I would argue that it is more like a container."
>>
>> Those (maybe unintentionally) are general statements about the range
>> concept rather than a specific one about iterator_range.
>
> This is all based on the following - the first line in the *current* docs for
> boost.range.
>
> "A Range is a concept similar to the STL Container concept."
>
> The same pre-amble goes on to talk about the differences between a
> range and a container; for example it says:
>
> "In particular, a Range does not necessarily
>
> * own the elements that can be accessed through it,
> * have copy semantics, "

That sounds familiar. In other words, a container has copy semantics
and owns its elements.

> It doesn't say that a range doesn't have a concept of emptiness,

But a range *does* have a concept of emptiness!

> or that it has properties of an iterator. This is why I have been
> contending that ranges are more container like than they are iterator
> like. I'm not making this up - it's what the docs tell me.

I understand that you feel the docs gave you reason to think that, but
IMO drawing that conclusion from the docs you cite is a stretch at best.
But you don't want to talk about philosophy, so let's drop it.

>>> I don't think containers in general have a single "defining feature".
>>> I agree that owning the data is a common feature of many containers,
>>> but so is the interface they have. A lot of containers have a
>>> superset of the interface we see on boost::iterator_range.
>>
>> If you're going to argue about peoples' expectations for a category of
>> types based on its similarity to some notion of "container," you at
>> least have to make reference to some commonly-understood definition of
>> the term. I chose the one in the standard, because that's what we all
>> have access to.
>
> Ok then - based on the contents of the docs here:
> http://www.boost.org/doc/libs/1_37_0/libs/range/doc/range.html what
> does that page mean? I'm basing the similarity on what the docs tell
> me to expect - are the docs wrong?

To the extent to which they imply that every default-constructed Range
should be testable for emptiness, yes. But frankly, I don't see such an
implication in that text except as a stretch. You have just as much
reason to expect all Ranges to have begin() and end() members (they
don't, in general) and Allocator template arguments (ditto), and
insert() members, etc.

And now we're back to philosophy. So, sorry.

>>>>>> It's unfortunate that the original implementation of iterator_range
>>>>>> set up different expectations for you, 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.
>>>>>
>>>>> And an empty() and a size()
>>>>
>>>> Okay, fine, but with a different (free function) syntax.
>>>
>>> empty() and size() on an iterator_range are both member functions - so
>>> I'm not sure what you mean here. Boost::iterator_range also provides
>>> front and back.
>>
>> Yes, but now you've switched backfrom talking about the range concept
>> to talking about a specific model of that concept.
>
> Are you surprised?

Not insofar as you and I seem to have very different ideas about what
constitutes a valid argument here.

> That's the original topic of this thread, and the key point. Again -
> this is precisely why I stopped posting to boost development a long
> time back - a simple problem becomes a lengthy philosophical
> discussion.

If you want to stick with iterator_range I'm more than happy to.
"Philosophy" in this conversation exists only because you made
assertions about the Range concept that I can't accept.

> I'm not talking about anything complex here. I've read the docs, I've
> looked at the code, I've used the code. Somewhere along the way we
> seem to now need exact definitions of iterator, container, range, and
> a whole host of other things in order to figure out how to resolve an
> undocumented breaking change.

Absolutely. I can't even begin to imagine how to resolve questions of
whether the thing is broken in the first place without precise
definitions. Sorry, I know I'm very literal-minded, but I don't know
another way to thing these issues through.

>>> The most obvious solution to this is 2 versions of the iterator_range
>>> class.
>>
>> Yes, if Tom needs the old behavior, he should have it. The question is,
>> how should he get it? He could write it himself, or Boost could provide
>> it in any number of ways.
>>
>> I think if I were the Range library maintainer, I would feel responsible
>> enough for my initial design mistake to have made this transition a lot
>> easier for my users, and I'd be bending over backwards to make up for
>> the breakage. I would also be very reluctant to maintain the old design
>> as anything more than a deprecated feature, though, because --- in my
>> opinion --- it is fundamentally flawed.
>
> So by that statement, you are saying that Tom's use case, which relied
> on the old behaviour, is fundamentally flawed?

No.

>>>>> It is; however, what the library intends it to be.
>>>>
>>>> Hm?
>>>
>>> That assertion comes from the comment in the code that says
>>> iterator_range is container-like.
>>
>> Apparently the "intentions of the library" are a bit like the
>> shifting sands.
>
> Why then do the docs still assert that a range is container-like?
> That's the 1.37 docs, not the 1.34 docs.

I can't account for the way the thing is documented. Do you really
think that one of the two designs in question was inconsistent with
Thorsten's intentions when he wrote it?

>> Incidentally, Tom cannot have both behaviors under the same name
>> (including namespace) without either violating the ODR or introducing
>> still more runtime overhead, thread safety problems, and other global
>> state evil. If he is going to use both behaviors, I'd prefer he use the
>> new behavior under the existing name and use a different name elsewhere.
>> If that was indeed a viable option for him (though I expect it's not),
>> the workaround would be easy: provide his own old_iterator_range
>
> I realise that - which was why I believe 2 versions under different
> names is by far and away the best way to resolve this. From my
> perspective I don't much care what they are each called, but I do
> strongly believe (in the absence of a better solution) that 2 versions
> is the way forward.

Okay, but should they both be in Boost, now that the damage is done?
I'm not sure that's the right answer either. And, by the way, I'm not
saying it's the wrong answer; I'm saying I haven't been convinced in
either direction.

If Tom isn't prepared to accept using boost::old_iterator_range instead
of boost::iterator_range, we have to break a bunch of other peoples'
code, which seems worse to me. Then both groups of users will have been
disrupted. If Tom *is* prepared to use boost::old_iterator_range, IMO
it may as well be tom::iterator_range: we don't have to have this
component in Boost at all, except as an example along with the change
notes that tell you how to write a component with the old behavior if
you need it.

-- 
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