Boost logo

Boost Users :

Subject: Re: [Boost-users] [range] questions about documentation and usage
From: Robert Ramey (ramey_at_[hidden])
Date: 2012-11-04 16:42:01


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.

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

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

>>> On might think to add something like:
>>> namespace boost {
>>> template <class T>
>>> boost::range_iterator<X>::type begin(T &t){
>>> return;
>>> }
>>> } // namespace boost
>>>
>>> But that raises a few design questions of it's own.
>>> 1) What should go into X?
>>> 2) this will match just about anything - which will likely create
>>> other design problems.

>> My comments above illustrate that the description/design of the
>> SinglePassRange concept is not comprehensible on its own.
>> Sounds like you agree with that.

> For the record, I do not.

I'm sorry I've failed to convince you, my attempt has been sincere though.

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

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

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

>
> [...snip more discussion on what belongs in the concept
> documentation...]
>
>> 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/

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

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

Robert Ramey


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