digitalmars.D.learn - RefRange
- David <d dav1d.de> Aug 26 2012
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> Aug 26 2012
- David <d dav1d.de> Aug 26 2012
- Jonathan M Davis <jmdavisProg gmx.com> Aug 26 2012
- Jonathan M Davis <jmdavisProg gmx.com> Aug 26 2012
- David <d dav1d.de> Aug 26 2012
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> Aug 26 2012
- David <d dav1d.de> Aug 26 2012
- David <d dav1d.de> Aug 26 2012
- "Era Scarecrow" <rtcvb32 yahoo.com> Aug 26 2012
- "Jonathan M Davis" <jmdavisProg gmx.com> Aug 27 2012
- "Era Scarecrow" <rtcvb32 yahoo.com> Aug 27 2012
It's a RefRange, but not completly ... Can somebody explain me that behaviour? http://dpaste.dzfl.pl/643de2a3
Aug 26 2012
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
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
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
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
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
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
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
On 08/26/2012 02:46 PM, David wrote:Sorry, dmd 2.060
Hmmm. I use 2.060 as well. Ali
Aug 26 2012
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
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
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









David <d dav1d.de> 