www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - RefRange

reply David <d dav1d.de> writes:
It's a RefRange, but not completly ... Can somebody explain me that 
behaviour?

http://dpaste.dzfl.pl/643de2a3
Aug 26 2012
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/26/2012 08:41 AM, David wrote:
 It's a RefRange, but not completly ... Can somebody explain me that
 behaviour?

 http://dpaste.dzfl.pl/643de2a3

According to its documentation, RefRange works differently whether the original range is a ForwardRange or not: http://dlang.org/phobos/std_range.html#refRange I have made TestRange a ForwardRange but then I had to comment out two lines of your program. Does it work according to your expectations with this change? import std.stdio; import std.range; struct TestRange { float[] x = [0, 1, 2, 3, 4, 5]; property bool empty() { return x.length == 0; } property ref float front() { return x[0]; } void popFront() { //writefln("before: %s", x); x = x[1..$]; //x.popFront(); //writefln("after: %s", x); } TestRange save() property { return TestRange(x); } } void main() { static assert(isForwardRange!TestRange); TestRange r = TestRange(); auto rr = refRange(&r); // foreach(element; rr) {} // writefln("Original range: %s", r.x); // writefln("RefRange: %s", rr.x); writefln("%s - %s", r.x.ptr, r.x.ptr); rr.popFront(); writefln("%s - %s", r.x.ptr, r.x.ptr); writefln("Original range: %s", r.x); // We can't expect the RefRange to have the members of the original range // writefln("RefRange: %s", rr.x); r.popFront(); writefln("%s - %s", r.x.ptr, r.x.ptr); writefln("Original range: %s", r.x); // We can't expect the RefRange to have the members of the original range // writefln("RefRange: %s", rr.x); } Ali
Aug 26 2012
parent David <d dav1d.de> writes:
Am 26.08.2012 18:06, schrieb Ali Çehreli:
 On 08/26/2012 08:41 AM, David wrote:
 It's a RefRange, but not completly ... Can somebody explain me that
 behaviour?

 http://dpaste.dzfl.pl/643de2a3

According to its documentation, RefRange works differently whether the original range is a ForwardRange or not: http://dlang.org/phobos/std_range.html#refRange I have made TestRange a ForwardRange but then I had to comment out two lines of your program. Does it work according to your expectations with this change? import std.stdio; import std.range; struct TestRange { float[] x = [0, 1, 2, 3, 4, 5]; property bool empty() { return x.length == 0; } property ref float front() { return x[0]; } void popFront() { //writefln("before: %s", x); x = x[1..$]; //x.popFront(); //writefln("after: %s", x); } TestRange save() property { return TestRange(x); } } void main() { static assert(isForwardRange!TestRange); TestRange r = TestRange(); auto rr = refRange(&r); // foreach(element; rr) {} // writefln("Original range: %s", r.x); // writefln("RefRange: %s", rr.x); writefln("%s - %s", r.x.ptr, r.x.ptr); rr.popFront(); writefln("%s - %s", r.x.ptr, r.x.ptr); writefln("Original range: %s", r.x); // We can't expect the RefRange to have the members of the original range // writefln("RefRange: %s", rr.x); r.popFront(); writefln("%s - %s", r.x.ptr, r.x.ptr); writefln("Original range: %s", r.x); // We can't expect the RefRange to have the members of the original range // writefln("RefRange: %s", rr.x); } Ali

Yes, that does it, but .save doesn't play well with RefRange (a static assert inside RefRange fails, telling that the produced RefRange-Type is not a ForwardRange).
Aug 26 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, August 26, 2012 17:41:45 David wrote:
 It's a RefRange, but not completly ... Can somebody explain me that
 behaviour?

 http://dpaste.dzfl.pl/643de2a3

refRange simply returns the original range if it's an input range rather than a forward range, since normally, when you have an input range, it isn't a value type, and there's no way to copy it, so operating on one reference of it is already the same as operating on all of them, making RefRange pointless. However, you've done the odd thing of declaring a value type input range. I don't know why that would ever be done except through ignorance of how ranges work. So, refRange is actually returning a copy in your case, which is why you're having problems. And by the way, the only reason that rr.x works is because refRange is returning a copy rather than a RefRange!TestRange. - Jonathan M Davis
Aug 26 2012
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, August 26, 2012 10:17:13 Jonathan M Davis wrote:
 On Sunday, August 26, 2012 17:41:45 David wrote:
 It's a RefRange, but not completly ... Can somebody explain me that
 behaviour?
 
 http://dpaste.dzfl.pl/643de2a3

refRange simply returns the original range if it's an input range rather than a forward range, since normally, when you have an input range, it isn't a value type, and there's no way to copy it, so operating on one reference of it is already the same as operating on all of them, making RefRange pointless. However, you've done the odd thing of declaring a value type input range. I don't know why that would ever be done except through ignorance of how ranges work. So, refRange is actually returning a copy in your case, which is why you're having problems.

Though the fact that you ran into this issue may indicate that having refRange return the original if it isn't a forward range was a bad decision. I don't know. In the normal case, it's definitely better, because it avoids an unnecessary wrapper, but obviously, people can make mistakes. You should still be able use RefRange with an input range though, as long as you use it directly. auto wrapped = RefRange!TestRange(&orig); But it would be better IMHO to just fix it so that your range is a forward range, since there's no reason for it not to be. - Jonathan M Davis
Aug 26 2012
parent reply David <d dav1d.de> writes:
Am 26.08.2012 20:07, schrieb Jonathan M Davis:
 On Sunday, August 26, 2012 10:17:13 Jonathan M Davis wrote:
 On Sunday, August 26, 2012 17:41:45 David wrote:
 It's a RefRange, but not completly ... Can somebody explain me that
 behaviour?

 http://dpaste.dzfl.pl/643de2a3

refRange simply returns the original range if it's an input range rather than a forward range, since normally, when you have an input range, it isn't a value type, and there's no way to copy it, so operating on one reference of it is already the same as operating on all of them, making RefRange pointless. However, you've done the odd thing of declaring a value type input range. I don't know why that would ever be done except through ignorance of how ranges work. So, refRange is actually returning a copy in your case, which is why you're having problems.

Though the fact that you ran into this issue may indicate that having refRange return the original if it isn't a forward range was a bad decision. I don't know. In the normal case, it's definitely better, because it avoids an unnecessary wrapper, but obviously, people can make mistakes. You should still be able use RefRange with an input range though, as long as you use it directly. auto wrapped = RefRange!TestRange(&orig); But it would be better IMHO to just fix it so that your range is a forward range, since there's no reason for it not to be. - Jonathan M Davis

Ranges died another time for me. This refRange copy thingy cost me lots of time, then I tried to implement a .save method, which uhm, just didn't work together with RefRange (isForwardRange!T succeeded, but isForwardRange!(RefRange!T) failed). Anyways, thanks for your explanations!
Aug 26 2012
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/26/2012 02:21 PM, David wrote:

 I tried to implement a .save method, which uhm, just
 didn't work together with RefRange (isForwardRange!T succeeded, but
 isForwardRange!(RefRange!T) failed).

What version of dmd? What is the code? When I add the following lines to the beginning of main() of the program that I have used in my other post, they both pass: static assert(isForwardRange!TestRange); static assert(isForwardRange!(RefRange!TestRange)); Ali
Aug 26 2012
parent reply David <d dav1d.de> writes:
Am 26.08.2012 23:33, schrieb Ali Çehreli:
 On 08/26/2012 02:21 PM, David wrote:

  > I tried to implement a .save method, which uhm, just
  > didn't work together with RefRange (isForwardRange!T succeeded, but
  > isForwardRange!(RefRange!T) failed).

 What version of dmd? What is the code?

 When I add the following lines to the beginning of main() of the program
 that I have used in my other post, they both pass:

      static assert(isForwardRange!TestRange);
      static assert(isForwardRange!(RefRange!TestRange));

 Ali

DMD 2.059 and: https://github.com/Dav1dde/BraLa/blob/7440688038bfd50a06fd9a49b8e9b6d08c7b4c28/brala/utils/queue.d But I don't care anylonger, I rewrote the whole Queue class (now it's a "real" queue, e.g. you can wait until all items are used up, with core.sync.condtion), I also don't feel like wasting more time in ranges, when I don't need them.
Aug 26 2012
parent reply David <d dav1d.de> writes:
Sorry, dmd 2.060
Aug 26 2012
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/26/2012 02:46 PM, David wrote:
 Sorry, dmd 2.060

Hmmm. I use 2.060 as well. Ali
Aug 26 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Sunday, 26 August 2012 at 18:07:27 UTC, Jonathan M Davis wrote:
 But it would be better IMHO to just fix it so that your range 
 is a forward range, since there's no reason for it not to be.

That brings up my own question. I'm writing an application that will end up using an output range (likely an appender, so semi-dynamic). How will I be sure that what's passed to other functions will append to the range? And more importantly, if I use save and then rewrite an earlier section (due to updated information) would that also be correct assuming memory didn't change on it? Can you give an example? Currently my code goes something like this: struct ... { innerType[] someInnerType; void write(T)(T outputRange) if(isForwardRange!(T)){ auto firstBlock = outputRange.save; //write to outputRange, first output will be re-written writeFirstBlock(outputRange); foreach(ref i; someInnerType) { i.write(outputRange); } //updated information for first block writeFirstBlock(save); } }
Aug 26 2012
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Sunday, August 26, 2012 23:20:49 Era Scarecrow wrote:
 On Sunday, 26 August 2012 at 18:07:27 UTC, Jonathan M Davis wrote:
 But it would be better IMHO to just fix it so that your range
 is a forward range, since there's no reason for it not to be.

That brings up my own question. I'm writing an application that will end up using an output range (likely an appender, so semi-dynamic). How will I be sure that what's passed to other functions will append to the range? And more importantly, if I use save and then rewrite an earlier section (due to updated information) would that also be correct assuming memory didn't change on it? Can you give an example? Currently my code goes something like this: struct ... { innerType[] someInnerType; void write(T)(T outputRange) if(isForwardRange!(T)){ auto firstBlock = outputRange.save; //write to outputRange, first output will be re-written writeFirstBlock(outputRange); foreach(ref i; someInnerType) { i.write(outputRange); } //updated information for first block writeFirstBlock(save); } }

I don't think that I really understand the question, but I'd be worried about intermixing save with operating on a range as an output range. It _should_ work, but save was designed with reading in mind, not writing. An output range doesn't have to have save or even front or popFront. All it needs is to work with put. Output ranges are a very different beast from input ranges, even if input ranges can be output ranges. That being said, I'd expect that save would save the current state, and any writing to the original would not affect the saved range. - Jonathan M Davis
Aug 27 2012
prev sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Monday, 27 August 2012 at 20:46:18 UTC, Jonathan M Davis wrote:
 I don't think that I really understand the question, but I'd be 
 worried about intermixing save with operating on a range as an 
 output range. It _should_ work, but save was designed with 
 reading in mind, not writing. An output range doesn't have to 
 have save or even front or popFront. All it needs is to work 
 with put. Output ranges are a very different beast from input 
 ranges, even if input ranges can be output ranges.

 That being said, I'd expect that save would save the current 
 state, and any writing to the original would not affect the 
 saved range.

Well the first block actually holds size information and the information it holds is the old information, stuff may have been added or taken away, so hopefully not to have to do two passes (a dummy pass and then a real one) I was hoping save would save the location. If it doesn't reference the previous location using the current data then I'll need to figure something out. It's this that's been holding off one of my projects for a while as I'm not sure how to best approach it.
Aug 27 2012