www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - RefRange

reply Jonathan M Davis <jmdavisProg gmx.com> writes:
I ran into a situation where I needed a forward range which was not a 
reference type to be consumed by a range-based function. Input ranges and 
reference type forward ranges are automatically and unavoidably consumed by 
range-based functions (assuming that save isn't called on them before the 
function starts consuming them), but that doesn't happen for either value type 
ranges or arrays. Hence my wrapper type (called RefRange). The code is here:

http://codepad.org/nNB4mAdN

I was wondering what other people's take on it was and whether I missed 
something which makes it a bad idea. Essentially, it's a range with a pointer 
to the original range so that any function calls on the wrapper affect the 
original range (and vice versa).

Assuming that no one pokes a major hole in it, and others think that it's a 
worthwhile addition, I'll create a pull request for it to be added to 
std.range. But I'd like other people's feedback on it first.

- Jonathan M Davis
Jun 13 2012
parent reply "Lars T. Kyllingstad" <public kyllingen.net> writes:
On Thursday, 14 June 2012 at 04:14:02 UTC, Jonathan M Davis wrote:
 I ran into a situation where I needed a forward range which was 
 not a
 reference type to be consumed by a range-based function. Input 
 ranges and
 reference type forward ranges are automatically and unavoidably 
 consumed by
 range-based functions (assuming that save isn't called on them 
 before the
 function starts consuming them), but that doesn't happen for 
 either value type
 ranges or arrays. Hence my wrapper type (called RefRange). The 
 code is here:

 http://codepad.org/nNB4mAdN

 I was wondering what other people's take on it was and whether 
 I missed
 something which makes it a bad idea. Essentially, it's a range 
 with a pointer
 to the original range so that any function calls on the wrapper 
 affect the
 original range (and vice versa).

 Assuming that no one pokes a major hole in it, and others think 
 that it's a
 worthwhile addition, I'll create a pull request for it to be 
 added to
 std.range. But I'd like other people's feedback on it first.
It is definitely a good idea. Basically, it provides the opposite guarantee of save(). If you're going to use the range once and then throw it away, and therefore don't care whether it is consumed or not, just use it directly. If you want to ensure it does not get consumed, use a copy obtained through save(). If you want to ensure it *does* get consumed, use a reference to it. However, someone pointed out here earlier that, since D uses the dot operator for pointer dereferencing, a pointer to a range is also a range. It just isn't recognised as such by foreach. So if we could just fix foreach, and maybe add functions providing range primitives for T[]* to std.array, I don't think we need a separate RefRange. Just take the address of the range when you want to ensure it gets consumed. -Lars
Jun 13 2012
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, June 14, 2012 07:35:35 Lars T. Kyllingstad wrote:
 On Thursday, 14 June 2012 at 04:14:02 UTC, Jonathan M Davis wrote:
 I ran into a situation where I needed a forward range which was
 not a
 reference type to be consumed by a range-based function. Input
 ranges and
 reference type forward ranges are automatically and unavoidably
 consumed by
 range-based functions (assuming that save isn't called on them
 before the
 function starts consuming them), but that doesn't happen for
 either value type
 ranges or arrays. Hence my wrapper type (called RefRange). The
 code is here:
 
 http://codepad.org/nNB4mAdN
 
 I was wondering what other people's take on it was and whether
 I missed
 something which makes it a bad idea. Essentially, it's a range
 with a pointer
 to the original range so that any function calls on the wrapper
 affect the
 original range (and vice versa).
 
 Assuming that no one pokes a major hole in it, and others think
 that it's a
 worthwhile addition, I'll create a pull request for it to be
 added to
 std.range. But I'd like other people's feedback on it first.
It is definitely a good idea. Basically, it provides the opposite guarantee of save(). If you're going to use the range once and then throw it away, and therefore don't care whether it is consumed or not, just use it directly. If you want to ensure it does not get consumed, use a copy obtained through save(). If you want to ensure it *does* get consumed, use a reference to it. However, someone pointed out here earlier that, since D uses the dot operator for pointer dereferencing, a pointer to a range is also a range. It just isn't recognised as such by foreach. So if we could just fix foreach, and maybe add functions providing range primitives for T[]* to std.array, I don't think we need a separate RefRange. Just take the address of the range when you want to ensure it gets consumed.
I don't think that that would work with save or opSlice though. Granted, save and opSlice _can_ make it so that the range isn't consumed like you'd like, depending on how the function that you're passing it to is implemented, but having RefRange implement save and opSlice is still useful, and is actually necessary if you want it to work as RandomAccessRange and the like (since all of the more complex ranges are forward ranges). So, if that won't work with a pointer (and I don't think that it will, since the type would be completely wrong), then you'd still need a type like RefRange. - Jonathan M Davis
Jun 13 2012
parent "Lars T. Kyllingstad" <public kyllingen.net> writes:
On Thursday, 14 June 2012 at 05:45:50 UTC, Jonathan M Davis wrote:
 On Thursday, June 14, 2012 07:35:35 Lars T. Kyllingstad wrote:
 However, someone pointed out here earlier that, since D uses 
 the
 dot operator for pointer dereferencing, a pointer to a range is
 also a range.  It just isn't recognised as such by foreach.  So
 if we could just fix foreach, and maybe add functions providing
 range primitives for T[]* to std.array, I don't think we need a
 separate RefRange.  Just take the address of the range when you
 want to ensure it gets consumed.
I don't think that that would work with save or opSlice though. Granted, save and opSlice _can_ make it so that the range isn't consumed like you'd like, depending on how the function that you're passing it to is implemented, but having RefRange implement save and opSlice is still useful, and is actually necessary if you want it to work as RandomAccessRange and the like (since all of the more complex ranges are forward ranges). So, if that won't work with a pointer (and I don't think that it will, since the type would be completely wrong), then you'd still need a type like RefRange.
Ah, that's true, of course. Indexing and slicing would be a disaster if one tried to do it with a pointer to a range. :) Then we should definitely have a RefRange. I actually suggested the very same thing on the Phobos ML myself once, but Andrei argued it would be better to define a more general Ref type, which works with all kinds of types, and not just ranges. Personally, I would be happy with something just for ranges. -Lars
Jun 13 2012