[boost.range] RFC on small updates

Hi All, I have planned to add a few extra convenience function to iterator_range and sub_range. Some people have said the classes could have been a little easier to use. The changes I suggest are the following: iterator_range: -------------- value_type& front() const; value_type& back() const; value_type& operator[]( size_type ) const; value_type& at( size_type ) const; void advance( size_type ); void narrow( size_type left, size_type right ); iterator_range& operator++(); value_type& operator*() const; sub_range: ---------- the same, but now constness is propagated freestanding: ------------ iterator_range make_sub_range( range&, size_type left, size_type right = 0 ); iterator_range make_super_range( range&, size_type left, size_type right = 0 ); iterator_range make_range( range&, difference_type left, difference_type right = 0 ); Comments? -Thorsten

Thorsten Ottosen wrote:
freestanding: ------------
iterator_range make_sub_range( range&, size_type left, size_type right = 0 ); iterator_range make_super_range( range&, size_type left, size_type right = 0 ); iterator_range make_range( range&, difference_type left, difference_type right = 0 );
Could you say what each of these does? Jonathan

"Jonathan Turkanis" <technews@kangaroologic.com> wrote in message news:ctoves$kg0$1@sea.gmane.org... | Thorsten Ottosen wrote: | | > | > freestanding: | > ------------ | > | > iterator_range make_sub_range( range&, size_type left, size_type | > right = 0 ); advances begin(r) and decreases end(r) to produce a smaller range | iterator_range make_super_range( range&, size_type left, | > size_type right = 0 ); decreases begin(r) and advances end(r) to produce a larger range | > iterator_range make_range( range&, difference_type left, | > difference_type right = 0 ); does advance( begin(r), left ) and advance( end(r), right ) and is thus the most general. | Could you say what each of these does? HIH, -Thorsten

Thorsten Ottosen wrote:
"Jonathan Turkanis" <technews@kangaroologic.com> wrote in message news:ctoves$kg0$1@sea.gmane.org...
Thorsten Ottosen wrote:
Thanks for the clarifications.
iterator_range make_sub_range( range&, size_type left, size_type right = 0 );
advances begin(r) and decreases end(r) to produce a smaller range
Since you have a template iterator_range and a corresponding object generator amke_iterator_range, I would expect make_sub_range to be an object generator returning a sub_range. So I would prefer the name "restrict_range"
iterator_range make_super_range( range&, size_type left, size_type right = 0 );
decreases begin(r) and advances end(r) to produce a larger range
How about "extend_range"?
iterator_range make_range( range&, difference_type left, difference_type right = 0 );
does advance( begin(r), left ) and advance( end(r), right ) and is thus the most general.
I'm not sure I see why you need all three functions, particularly this last one.
-Thorsten
Jonathan

"Jonathan Turkanis" <technews@kangaroologic.com> wrote in message news:ctp3dr$efm$1@sea.gmane.org... | Thorsten Ottosen wrote: | > "Jonathan Turkanis" <technews@kangaroologic.com> wrote in message | > news:ctoves$kg0$1@sea.gmane.org... | >> Thorsten Ottosen wrote: | | Thanks for the clarifications. | | >> iterator_range make_sub_range( range&, size_type left, size_type | >> right = 0 ); | > | > advances begin(r) and decreases end(r) | > to produce a smaller range | | Since you have a template iterator_range and a corresponding object generator | amke_iterator_range, I would expect make_sub_range to be an object generator | returning a sub_range. that is true...maybe we should add those? | So I would prefer the name "restrict_range" | | >> iterator_range make_super_range( range&, size_type left, | >> size_type right = 0 ); | > | > decreases begin(r) and advances end(r) | > to produce a larger range | | How about "extend_range"? maybe narrow_range() and widen_range() and then cut away the narrow member function? | >> iterator_range make_range( range&, difference_type left, | >> difference_type right = 0 ); | > | > does advance( begin(r), left ) and advance( end(r), right ) | > and is thus the most general. | | I'm not sure I see why you need all three functions, particularly this last one. yeah, I suspect that it would used infrequently. I just wanted to hear what you all thought. br -Thorsten

Hi Thorsten, On Tue, Feb 01, 2005 at 11:07:56PM +0100, Thorsten Ottosen wrote:
Hi All,
I have planned to add a few extra convenience function to iterator_range and sub_range. Some people have said the classes could have been a little easier to use. The changes I suggest are the following:
iterator_range: --------------
value_type& front() const; value_type& back() const; value_type& operator[]( size_type ) const; value_type& at( size_type ) const;
These functions seems usefull. However, I think, that operator[] should be available only when underlaying iterator is random-access like
void advance( size_type ); void narrow( size_type left, size_type right ); iterator_range& operator++(); value_type& operator*() const;
I assume, that these are inspired by John Torjo's RTL. I'm not very keen of them, since I consider the using of an iterator_range instead of iterator confusing. But it is only my personal opinion. I would rather include this functionality elsewhere (iterator lib?)
sub_range: ----------
the same, but now constness is propagated
freestanding: ------------
iterator_range make_sub_range( range&, size_type left, size_type right = 0 ); iterator_range make_super_range( range&, size_type left, size_type right = 0 ); iterator_range make_range( range&, difference_type left, difference_type right = 0 );
Generaly the same issue as above applies. However, I find these functions not so offending. There might be a use for the them (last one especialy). What I find important when including such a functions is to make sure, you don't get into the problems with less capable iterators. (i.e that you don't disable the iterator_range for forward-only iterators for instance) Regards, Pavol.

"Pavol Droba" <droba@topmail.sk> wrote in message | > iterator_range: | > -------------- | > | > value_type& front() const; | > value_type& back() const; | > value_type& operator[]( size_type ) const; | > value_type& at( size_type ) const; | > | | These functions seems usefull. However, I think, that operator[] should | be available only when underlaying iterator is random-access like yes, it won't compile otherwise. | > void advance( size_type ); | > void narrow( size_type left, size_type right ); | > iterator_range& operator++(); | > value_type& operator*() const; | > | | I assume, that these are inspired by John Torjo's RTL. I'm not very keen of them, | since I consider the using of an iterator_range instead of iterator confusing. Ok, so here's how I was thinking: if we add, let's say, only operator++() and operator*(), then we get a very simple way to iterate over the range... manual loops are still very inconvenient in C++. (Yes, BOOST_FOREACH willl improve things a lot). Anyway, currently you would have to write for( typename range_iterator<Range>::type i = r.begin(), e = r.end(); ++i ) { ... } with the new stuff we simply say for( ; r, ++r ) { ... } If you consider sub_range<>, then we get a new kind of "iterator" that actually propagates constness, so it might complement iterator and const_iterator. | > freestanding: | > ------------ | > | > iterator_range make_sub_range( range&, size_type left, size_type right = 0 ); | > iterator_range make_super_range( range&, size_type left, size_type right = | > 0 ); | > iterator_range make_range( range&, difference_type left, difference_type right | > = 0 ); | > | | Generaly the same issue as above applies. However, I find these functions | not so offending. There might be a use for the them (last one especialy). ok. | What I find important when including such a functions is to make sure, | you don't get into the problems with less capable iterators. | (i.e that you don't disable the iterator_range for forward-only iterators | for instance) ah well, there is no magic in these functions, they work by calling std::advance() and will work for all forward iterators. they will of couse not work for single-pass iterators. -Thorsten

Thorsten Ottosen writes:
I have planned to add a few extra convenience function to iterator_range and sub_range. Some people have said the classes could have been a little easier to use. The changes I suggest are the following:
iterator_range: --------------
value_type& front() const; value_type& back() const; value_type& operator[]( size_type ) const;
Assuming that 'operator[]' is provided only for Random Access iterators, the above three are very reasonable.
value_type& at( size_type ) const;
Is it a checked version of 'operator[]'?
void advance( size_type ); void narrow( size_type left, size_type right ); iterator_range& operator++(); value_type& operator*() const;
Please NO. 'narrow' can be a freestanding utility function, and the rest is at best a questionable "convenience" baggage with no value for generic code. Also, think "standardization". -- Aleksey Gurtovoy MetaCommunications Engineering

"Aleksey Gurtovoy" <agurtovoy@meta-comm.com> wrote in message news:m1fz0ff8q8.fsf@tulip.office.meta... | Thorsten Ottosen writes: | > I have planned to add a few extra convenience function to | > iterator_range and sub_range. Some people have said the classes | > could have been a little easier to use. The changes I suggest are the | > following: | > | > iterator_range: | > -------------- | > | > value_type& front() const; | > value_type& back() const; | > value_type& operator[]( size_type ) const; | | Assuming that 'operator[]' is provided only for Random Access | iterators, the above three are very reasonable. yes, only when the underlying range has randomaccessiterators. | > value_type& at( size_type ) const; | | Is it a checked version of 'operator[]'? yes. | > void advance( size_type ); | > void narrow( size_type left, size_type right ); | > iterator_range& operator++(); | > value_type& operator*() const; | | Please NO. 'narrow' can be a freestanding utility function, front() and back() are also easy to make freestanding, but the idea was that these two helper functions should be made just a little more convenient. So you don't think the iterator capabilities is worth the trouble? | and the | rest is at best a questionable "convenience" baggage with no value for | generic code. Also, think "standardization". Do you mean make_sub_range() and the others? br -Thorsten

Thorsten Ottosen writes:
| > value_type& at( size_type ) const; | | Is it a checked version of 'operator[]'?
yes.
I'm against it, then. If you want range checking for debugging purposes, all major standard library implementations offer a debug mode that is much better and consistent at that. If you want it to throw in release and yet don't want the rest of the checks offered by the debug mode, I'd like to see your use case.
| > void advance( size_type ); | > void narrow( size_type left, size_type right ); | > iterator_range& operator++(); | > value_type& operator*() const; | | Please NO. 'narrow' can be a freestanding utility function,
front() and back() are also easy to make freestanding,
True. But they actually _are_ often-used and are actually a part of the "standard" range interface; in contrast, in four years of our own 'iterator_range's life, we didn't need 'narrow' functionality often enough to factor it out into an utility function, let alone making it the class' member. FWIW.
but the idea was that these two helper functions should be made just a little more convenient.
I understand that, but then consider that there are may be ten more such convenience functions lurking out there. We certainly don't want 'iterator_range' to become another 'std::string', do we? Also consider that many of these utility functions are in fact applicable not only to iterator ranges, but to ranges in general. While we don't have a generic range library in Boost yet, it certainly wouldn't hurt to keep in mind a bigger picture.
So you don't think the iterator capabilities is worth the trouble?
They are just one possible workaround for the lack of 'foreach', hardly commonplace and arguably unidiomatic, and as such are at best of a subjective utility. Something like that might be offered by some other library that targets to compensate this language shortcoming, but they certainly don't belong to 'iterator_range'. Straightforward and uncontroversial is IMO what we should target for here.
| and the | rest is at best a questionable "convenience" baggage with no value for | generic code. Also, think "standardization".
Do you mean make_sub_range() and the others?
I meant iteration shortcuts (advance, ++ and *). I have no experience with subranges, and therefore have no opinion on that part of your post. -- Aleksey Gurtovoy MetaCommunications Engineering

"Aleksey Gurtovoy" <agurtovoy@meta-comm.com> wrote in message news:m1lla6dm6b.fsf@tulip.office.meta... | Thorsten Ottosen writes: | > | > void advance( size_type ); | > | > void narrow( size_type left, size_type right ); | > | > iterator_range& operator++(); | > | > value_type& operator*() const; | > | | > | Please NO. 'narrow' can be a freestanding utility function, | > but the idea was that these two helper functions should be made just | > a little more convenient. | | I understand that, but then consider that there are may be ten more | such convenience functions lurking out there. We certainly don't want | 'iterator_range' to become another 'std::string', do we? well, no, but std::string is extreame. | > So you don't think the iterator capabilities is worth the trouble? | | They are just one possible workaround for the lack of 'foreach', | hardly commonplace and arguably unidiomatic, and as such are at best | of a subjective utility. Something like that might be offered by some | other library that targets to compensate this language shortcoming, | but they certainly don't belong to 'iterator_range'. Straightforward | and uncontroversial is IMO what we should target for here. | | > | > | and the | > | rest is at best a questionable "convenience" baggage with no value for | > | generic code. Also, think "standardization". | > | > Do you mean make_sub_range() and the others? | | I meant iteration shortcuts (advance, ++ and *). in some sence operator*() is provided by operator[]()... I guess random access iterators will fit must use cases like strings. But OTOH, I don't see how two functions (let's scrap advance) can hurt at all, not even in a standardization context. -Thorsten

Thorsten Ottosen writes:
| > So you don't think the iterator capabilities is worth the trouble? | | They are just one possible workaround for the lack of 'foreach', | hardly commonplace and arguably unidiomatic, and as such are at best | of a subjective utility. Something like that might be offered by some | other library that targets to compensate this language shortcoming, | but they certainly don't belong to 'iterator_range'. Straightforward | and uncontroversial is IMO what we should target for here. | | > | > | and the | > | rest is at best a questionable "convenience" baggage with no value for | > | generic code. Also, think "standardization". | > | > Do you mean make_sub_range() and the others? | | I meant iteration shortcuts (advance, ++ and *).
in some sence operator*() is provided by operator[]()... I guess random access iterators will fit must use cases like strings. But OTOH, I don't see how two functions (let's scrap advance) can hurt at all, not even in a standardization context.
To put it bluntly, my point is that they are somebody's pet features (not necessarily yours, mind you), as opposite to functionality to support widely accepted, idiomatic usage. 'iterator_range' is too important to let it get greased with pet features. -- Aleksey Gurtovoy MetaCommunications Engineering

To put it bluntly, my point is that they are somebody's pet features (not necessarily yours, mind you), as opposite to functionality to support widely accepted, idiomatic usage. 'iterator_range' is too important to let it get greased with pet features.
Perhaps Aleksey is right. Your iterator_range is a concept different from mine. For instance, allowing ++pre, could beg for post++, and then (for bidirectional ranges) for --, and so on. As well for -- and such. Also, offering operator* would beg for operator-> However, the way I see it, if rangelib makes it into boost, at a later time, we might be able to merge these two libs. Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -v1.6.3 (Resource Splitter) -- http://www.torjo.com/cb/ - Click, Build, Run!

Aleksey Gurtovoy <agurtovoy@meta-comm.com> writes:
in some sence operator*() is provided by operator[]()... I guess random access iterators will fit must use cases like strings. But OTOH, I don't see how two functions (let's scrap advance) can hurt at all, not even in a standardization context.
To put it bluntly, my point is that they are somebody's pet features (not necessarily yours, mind you), as opposite to functionality to support widely accepted, idiomatic usage. 'iterator_range' is too important to let it get greased with pet features.
Seconded. Also, these operators are unsuitable for use in many generic contexts. Furthermore, can do all the same things with free functions that don't intrude on the purity of the range "concept". If you really like these idioms, using namespace range_operators; could be enough to make them available. Cheers -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Fri, Feb 04, 2005 at 09:53:02AM -0500, David Abrahams wrote:
Aleksey Gurtovoy <agurtovoy@meta-comm.com> writes:
in some sence operator*() is provided by operator[]()... I guess random access iterators will fit must use cases like strings. But OTOH, I don't see how two functions (let's scrap advance) can hurt at all, not even in a standardization context.
To put it bluntly, my point is that they are somebody's pet features (not necessarily yours, mind you), as opposite to functionality to support widely accepted, idiomatic usage. 'iterator_range' is too important to let it get greased with pet features.
Seconded. Also, these operators are unsuitable for use in many generic contexts.
Furthermore, can do all the same things with free functions that don't intrude on the purity of the range "concept". If you really like these idioms,
using namespace range_operators;
could be enough to make them available.
I absolutely agree with the above. I wouldn't be able to express it better. iterator_range was designed as a minimal utility class from the beginning. I consider these operations as a unnecessary feature bloat. The should not be there. Regards, Pavol.

Hi Thorsten,
iterator_range: --------------
value_type& front() const; value_type& back() const; value_type& operator[]( size_type ) const;
I'm all for having these.
value_type& at( size_type ) const;
I'm don't very much like having a throwing at() function. But this comes from the fact that I don't like vector's at() either. So, you can think of me as neutral on this one.
void advance( size_type ); void narrow( size_type left, size_type right );
I don't like these. I think this is much easier accomplished with the freestanding functions.
iterator_range& operator++(); value_type& operator*() const;
I'm all for it :) Out of curiosity, will you have ++pre and post++?
sub_range: ----------
same as above
freestanding: ------------
iterator_range make_sub_range( range&, size_type left, size_type right = 0 ); iterator_range make_super_range( range&, size_type left, size_type right = 0 ); iterator_range make_range( range&, difference_type left, difference_type right = 0 );
Yup, I'm all for all ;) My favorite would be the last one, and I've been meaning to implement it myself for rangelib. Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -v1.6.3 (Resource Splitter) -- http://www.torjo.com/cb/ - Click, Build, Run!

| > iterator_range& operator++(); | > value_type& operator*() const; | | I'm all for it :) | Out of curiosity, will you have ++pre and post++? I only thought of ++pre. -Thorsten

Thorsten Ottosen wrote:
| > iterator_range& operator++(); | > value_type& operator*() const; | | I'm all for it :) | Out of curiosity, will you have ++pre and post++?
I only thought of ++pre.
If you offer ++pre, I see no reason not to offer post++ as well. Best, John -- John Torjo, Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -v1.6.3 (Resource Splitter) -- http://www.torjo.com/cb/ - Click, Build, Run!

Hi All, Here's my conclusion of this small RFC: These function can be added: | iterator_range: | -------------- | | value_type& front() const; | value_type& back() const; | value_type& operator[]( size_type ) const; sub_range: - the same, but now constness is propagated freestanding: template< class Range > iterator_range make_iterator_range( Range&, typename range_difference<Range>::type, typename range_difference<Range>::type ); + one for const Range&. The last version is the most general and hence we don't need the two others. br Thorsten
participants (6)
-
Aleksey Gurtovoy
-
David Abrahams
-
John Torjo
-
Jonathan Turkanis
-
Pavol Droba
-
Thorsten Ottosen