Boost logo

Boost Users :

Subject: Re: [Boost-users] [range] questions about documentation and usage
From: Jeffrey Lee Hellrung, Jr. (jeffrey.hellrung_at_[hidden])
Date: 2012-11-04 18:05:26


On Sun, Nov 4, 2012 at 1:42 PM, Robert Ramey <ramey_at_[hidden]> wrote:

> Jeffrey Lee Hellrung, Jr. wrote:
> > On Sun, Nov 4, 2012 at 10:10 AM, Robert Ramey <ramey_at_[hidden]> wrote:
> >
> > Jeffrey Lee Hellrung, Jr. wrote:
> >> On Sun, Nov 4, 2012 at 1:37 AM, Robert Ramey <ramey_at_[hidden]> wrote:
> >>
> >> Neil Groves wrote:
> >>> On Sat, Nov 3, 2012 at 11:29 PM, Robert Ramey <ramey_at_[hidden]>
> >>> wrote:
>
> > IMHO, a strict reading of [5] does not necessitate that a concept
> > provide ways to allow the user to create models (e.g., write
> > archetypes).
>
> I believe a concept definition describes those valid expressions
> which necessary and SUFFICIENT to define the concept.
> That is, I think we'll agree that any type which models the
> concept should support all the valid expressions list. I belive
> also that any type which supports all the valid expressions
> listed is necessarily a model of the concept. Again, would
> appreciate input form a concept guru here.
>

Okay.

>> Is the documentation under [1] and/or [2] unclear?
> >
> > It is.
> >
> > Method 1 provides information I would have expected to find
> > in the SinglePassRange concept. I'm assuming that the member
> > functions and types would be members of any class modeling
> > SinglePassRange. I say "assuming becaus it doesn't actually
> > say that.
> >
> > Then...why are you assuming that?
>
> Because the documentation says they are member functions
> but it doesn't say of what type. One has no choice to guess
> or assume.

What do you mean "of what type"? Why do you need to guess or assume
anything? Method 1 just explains one way for a UDT to satisfy the Single
Pass Range concept, but it doesn't imply this is the *only* way (see Method
2).

Let me try to help. Method 1 can be summarized as:

--------
One way for class X to model the Single Pass Range concept is for X to
provide member functions X::begin/X::end and typedefs
X::iterator/X::const_iterator.
--------

This implies that all STL-style containers are automatically useable with
Boost.Range, since they fulfill these member requirements. But it does
*not* state the converse, i.e., that all classes which model Single Pass
Range must have begin/end member functions and iterator/const_iterator
typedefs. These member function requirements are sufficient, but not
necessary. For example, UDTs may hook into Boost.Range non-intrusively via
Method 2.

Does that help?

> In any case, these should be part of the
> > "valid expressions" section of the SinglePassRange concept.
>
> > *That* would be a mistake; begin/end member functions and an iterator
> > typedef are just sufficient for a type to model SPR, but they aren't
> > necessary. E.g., std::pair< int*, int* > is a valid range.
>
> SinglePassRangeConcept requires the valid expression
> boost::begin(a) if a instance the type which models the concept.
> I've been directed to "method 1" of the documentation. There
> one is directed to implement a member begin() of some
> unspecified type. I'm sorry, if I want to make my own range,
> I just don't know what to do to from reading this.
>

If you want to adapt your own UDT to be a Single Pass Range, either
(a) Use Method 1, i.e., define begin/end member functions and
iterator/const_iterator typedefs. By "some unspecified type", are you
referring to unspecified *signatures*? If so, yes, the documentation could
be more precise here. Honestly, familiarity with STL containers should get
most people past this underspecification.
or (b) Use Method 2, in the event that your type does not meet the
requirements of Method 1 and you must adapt the type extrinsically.

It may be beneficial for the documentation to explicitly make the
correspondence

boost::begin(x) <=> x.begin() [Method 1]
boost::begin(x) <=> range_begin(x) [Method 2]

within the respective documentation for Methods 1 and 2, but I would think
the intent is clear. Here, I mean that boost::begin(x) from the Single Pass
Range concept definition is equivalent to x.begin() if X fulfills the
requirements of Method 1, and likewise for Method 2, and likewise for the
range_iterator metafunction.

[...]

> >> I content that it should be considered
> >> a mistake. The fact that it raises these "other questions" proves
> >> that it's a mistake.
> >> The whole idea of concepts, functional programming or whatever
> >> one want's to call it is to permit the the composition of components
> >> which can be demonstrated correct when considered one at at time.
> >
> >> If you have to read the whole documentation to understand one
> >> one concept - or spelunk through the code - it's a red flag that
> >> some things are coupled where they shouldn't be.
>
> > No spelunking through code is necessary, you did that on your own.
>
> Only because I had to.
>
> > If you want to understand what you can do and how to use a concept, the
> > concept documentation is sufficient (IMO).
>
> Of course that's where we can't agree.
>

Actually, I haven't seen any argument on this point, it's the next one
that's contentious.

>If you want to create an
> > archetype or adapt an existing UDT to a concept, the extenstion
> > mechanism documentation is sufficient (IMO).
>
> To my mind, the way the "extension mechanism" is formulated is
> a symptom of the problem. Much of what's in there - should be
> part of the the SinglePassRange concept if the concept were
> correctly formulated.
>

Yes, your position is clear. See next response.

> > This is also how
> > Boost.Fusion and Boost.MPL (at least) are structured, AFAIK.
>
> I don't think that's accurate. If you want to make your own model
> of a concept, you just make sure your types implement all the valid
> expressions.
>

Maybe in your world. And maybe your world is the correct one. But compare
Boost.Fusion's Forward Sequence concept documentation [6] with its
extension mechanism documentation [7]; it parallels Boost.Range's
documentation. Boost.MPL is similar, only the documentation on its tag
dispatching mechanism is harder to find and (IMO) under-documented. And,
again, Boost.Parameter's documentation on its concepts [8] doesn't give any
indication that a UDT can or should model these concepts. I don't think any
of these concept documentations fit your idea of what a concept is. And
maybe they're all wrong (or I'm all wrong), I don't know. IMHO, I think
it's appropriate for the documentation to separate the concept definition
(how you use and what you can do with a model of a concept) from any
extension mechanisms (how you create a model of a concept), if said
extension mechanisms are non-trivial.

>> Of course this will ripple to boost::iterator_range so that we'll
> >> need template<class T>
> >> iterator_range {
> >> ...
> >> T begin();
> >> ...
> >> };
> >>
> >> But we already have that. So far so good.
> >
> >>> I don't follow. What relevance does iterator_range have here,
> >>> exactly?
> >
> >> I'm trying to demonstrate what I would expect the natural development
> >> of the library would be were it built concurrently with the
> documentation
> >> as I think is the best way to do it. It's meant as a constructive
> >> suggestion as to how to go about these things.
>
> > I'm sorry, I'm still not following. Can you be more concrete? I don't
> > know what you mean by building a library "concurrently with the
> > documentation", and I'm not sure what your suggestion about "how to
> > go about these things" actually is.
>
> rsd.com/blincubator.com/advice/
>

page not found

> >> Sorry, not following. Are you complaining that the boost::find call
> >> compiles, and you think it shouldn't (I agree, it probably
> >> shouldn't)?
> >
> > Correct.
> >
> > if for some type T, BOOST_CONCEPT_ASSERT((SinglePassRangeConcept<T>))
> > traps
> > then any function which requires it's parameters to model the concept
> > SinglePassRange
> > should also fail to compiler. This is because the implementation of f
> > find<T> should include the statement
> > BOOST_CONCEPT_ASSERT((SinglePassRangeConcept<T>)).
> > I see that find<T> does in fact include this. I can't see why it
> > traps when
> > called
> > directly but doesn't when called from within find. There's a mistake
> > in the implementation somewhere - (or maybe a dumb blunder in syntax).
> >
> >
> > Hmmm, works for me, as in, it fails to compile.
> >
> > --------
> > #include <boost/concept/assert.hpp>
> > #include <boost/range/algorithm/find.hpp>
> > #include <boost/range/concepts.hpp>
> >
> > struct X { };
> >
> > namespace boost
> > {
> > int const * begin(X&);
> > int const * end(X&);
> > } // namespace boost
> >
> > int main(int argc, char* argv[])
> > {
> > X x;
> > //boost::find(x, 0); // compiler error
> > boost::range::find(x, 0); // compiler error
> > return 0;
> > }
> > --------
> >
> > Same error comes up as in a BOOST_CONCEPT_ASSERT, pointing to a line
> > referencing range_const_iterator and range_mutable_iterator,
> > suggesting that Boost.Range cannot associate an iterator type with X.
> >
> >
> >> b) I thought that all the stuff was built directly in the boost
> >> namespace which I object to. I see it's really built in boost::range
> >> (much better) but hoisted up to namespace boost via a wrapper
> >> and using declaration. I have to observations about this:
> >> 1) I don't think using should every be in any header file.
> >
> >> Why not?
> >
> > because now a user is importing a whole bunch of names into
> > his lookup set without being informed of it.
> >
> >> Really, a "whole bunch"? It has a single "using range::find" that
> >> pulls boost::range::find into the boost namespace.
>
> OK - it imports names I don't know about into my application.
>

It's documented to define boost::find, which it does, so you must be
objecting to it also defining boost::range::find. Fine. Maybe it should
have been boost::range_detail::find. Anyways, your entire complaint about
this using declaration is a moving target. Let's drop it as...

>> How can this be
> >> any worse than defining boost::find directly in the boost namespace?
>
> I object to that as well. But at least if I include boost::find I'm
> getting
> what I'm asking for - not some other stuff I don't know about unless
> I look at the library implementation.
>
> >> It's actually way better this way as now boost::find will be less
> >> likely found via ADL.
>
> Better - but not good
>
> > AFAIK, boost::find is documented, and boost::range::find is not. It's
> > an implementation detail that, as I've said above, is no worse than
> > defining boost::find directly in the boost namespace.
>
> which I also object to.
>

...the real issue you have is that find (and other Boost.Range algorithms)
is directly in the boost namespace, which is a legitimate complaint. I at
least give credit to Neil and/or Thorsten that they were at least wise
enough to limit ADL problems via the using declaration. Also, boost::find
being a direct analogue of std::find is at least some rationale (some may
not think sufficient) for it residing directly in the boost namespace.

- Jeff

[6]
http://www.boost.org/doc/libs/1_51_0/libs/fusion/doc/html/fusion/sequence/concepts/forward_sequence.html
[7]
http://www.boost.org/doc/libs/1_51_0/libs/fusion/doc/html/fusion/extension/ext_full.html
[8]
http://www.boost.org/doc/libs/1_51_0/libs/parameter/doc/html/reference.html#concepts



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net