On Sun, Nov 4, 2012 at 1:42 PM, Robert Ramey
<ramey@rrsd.com> wrote:
Jeffrey Lee Hellrung, Jr. wrote:
> On Sun, Nov 4, 2012 at 10:10 AM, Robert Ramey <ramey@rrsd.com> wrote:
>
> Jeffrey Lee Hellrung, Jr. wrote:
>> On Sun, Nov 4, 2012 at 1:37 AM, Robert Ramey <ramey@rrsd.com> wrote:
>>
>> Neil Groves wrote:
>>> On Sat, Nov 3, 2012 at 11:29 PM, Robert Ramey <ramey@rrsd.com>
>>> 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]