
Andrew Sutton wrote:
I usually try (although don't always succeed) to distinguish this from
the example you are giving above, by talking about standard library containers in that context.
I'm not talking about standard library containers, in the sense of vector, list, deque, etc. I'm talking about the standard library definition of what it means to be a container.
In the context of the standard library. The standard library doesn't have a monopoly on the term container.
But it does define the *concept* of a 'Container' (with a capital 'C') which, in turn defines the syntax, semantics, and guarantees thereof within the context of the standard library. The same goes for Iterator and its refinements. Concepts are also going to be part of C++0x language so there should be no imprecision or ambiguity when talking about a Container.
Which we are not - we are talking about something which professes to be "container-like" therefore it isn't a container, and we shouldn't get hung up on the definition. My point is that containers can be more things to more people - and I think that is valid; although in this context, I'm not convinced the discussion is even relevant any more. boost.range in it's own documentation claims to provide something container-like - surely that should be enough?
The *notion* of a 'container' (with a lowercase 'c') can be substantially broader and mean different things to different people at different times. Unfortunately, it's hard to build reliable structures on shifting sand.
That's the problem we face as generic library programmers. Everything we ever write will get used by people for different things - building reliable structures on shifting sands is what makes the problem both hard and enjoyable (at least in my case).
These concepts (Container, Iterator, etc.) in the standard are the foundations of Boost.Range and every other generic library in Boost. Concepts are the language of generic libraries, and you can't expect to have meaningful discussions about them if you refuse to learn the language.
Yes - and the concepts of boost.range were changed without discussion from what they were on acceptance of the library into boost. Furthermore, the concepts that describe a boost.range aren't defined anywhere - despite being based on the principles of iterators and containers in the standard library. That's why, to a certain extent, it's the libraries role to try and define them. In this case, the definition has changed, and I am arguing that the change makes the range less container-like. That's not necessarily right or wrong, it's just different, and my argument has been that both routes might well be equally valid - hence why we should probably accept both solutions. In just the same way as the standard library accepts different features sets for say random access iterators and output iterators. They are both iterators, but they are very very different. In the same context, I would argue that we should accept both a version of range that can be default constructed to be empty, and one that can't - is that such a big problem?
Are you surprised? 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. 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.
To a degree, I think this is an unfortunate side-effect of building and maintaining generic libraries. If you don't get it exactly right the first time (both code and docs), then discussion of solutions absolutely must concern the definitions of concepts. Unfortunately, problems with Iterators (and by extension Ranges) tend to be lengthy and detailed since they're such fundamental concepts and can have far reaching impact.
And it's a real change that such a major change to the library went through without discussion. But, what we don't need is exact definitions of containers and iterators - what we need is a definition of a range, which the library tries to do. Unfortunately, when functionality changes and breaks people's code, those people lose confidence in the library and, quite often, either stop using it, or worse still, freeze on an old version and stop upgrading it. With boost that is more insidious since a library freeze tends to prevent newer libraries from being available. I've seen organisations get stuck on old versions of boost - hence why I recommended elsewhere in this thread that we should split boost into a core more stable part, and a new part; both with different release timescales. I'm disappointed that discussion hasn't been taken up as much as the philosophical one we seem to be bogged down in at the moment.
I'm not particularly fond of the is_singular() solution with preprocessed code, but It does appear to result in correct behavior when compiled for release - so I'm definitely not in favor of rolling out those changes. Other solutions have been proposed.
Well that is up for question since this discussion as yet hasn't seemed to decide what the correct behaviour is. Furthermore, different behaviour between release and debug is at best insidious. Dave