www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - error with std.range.put - readN

reply "Baz" <bb.temp gmx.com> writes:
the following program fails because of the `put` function :

---
import std.stdio;
import std.range;

size_t readN(T, Range)(ref Range src, ref Range dst, size_t n)
if (isInputRange!Range && isOutputRange!(Range, T))
{
     size_t result;

     while(1)
     {
         if (src.empty || result == n)
             break;

         put(dst, src.front()); // here
         src.popFront;

         ++result;
     }


     return result;
}

void main(string[] args)
{
     int[] src = [1,2,3];
     int[] dst = [0];

     auto n = readN!int(src, dst, 2);

     writeln(dst);
}
---

If i replace `put` by a cat op (`~`) it works, however the cat op 
only works here because i test the template with two int[].

What's wrong ?
May 04 2015
next sibling parent "sclytrack" <sclytrack fake.com> writes:
On Monday, 4 May 2015 at 14:33:23 UTC, Baz wrote:
 the following program fails because of the `put` function :

 ---
 import std.stdio;
 import std.range;

 size_t readN(T, Range)(ref Range src, ref Range dst, size_t n)
 if (isInputRange!Range && isOutputRange!(Range, T))
 {
     size_t result;

     while(1)
     {
         if (src.empty || result == n)
             break;

         put(dst, src.front()); // here
         src.popFront;

         ++result;
     }


     return result;
 }

 void main(string[] args)
 {
     int[] src = [1,2,3];
     int[] dst = [0];

     auto n = readN!int(src, dst, 2);

     writeln(dst);
 }
 ---

 If i replace `put` by a cat op (`~`) it works, however the cat 
 op only works here because i test the template with two int[].

 What's wrong ?
I believe the put(R,E) calls the doPut(R, E) private void doPut(R, E)(ref R r, auto ref E e) { //... else static if (isInputRange!R) { static assert(is(typeof(r.front = e)), "Cannot nativaly put a " ~ E.stringof ~ " into a " ~ R.stringof ~ "."); r.front = e; r.popFront(); } //... } So basically you put elements into the list until it is empty. import std.stdio; import std.range; void main() { int [] list = new int [10]; writeln(list); //10 zeros list.front = 5; //1 five and 9 zeroes writeln(list); list.popFront(); //9 zeroes left. writeln(list); }
May 04 2015
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, 4 May 2015 at 14:33:23 UTC, Baz wrote:
 the following program fails because of the `put` function :

 ---
 import std.stdio;
 import std.range;

 size_t readN(T, Range)(ref Range src, ref Range dst, size_t n)
 if (isInputRange!Range && isOutputRange!(Range, T))
 {
     size_t result;

     while(1)
     {
         if (src.empty || result == n)
             break;

         put(dst, src.front()); // here
         src.popFront;

         ++result;
     }


     return result;
 }

 void main(string[] args)
 {
     int[] src = [1,2,3];
     int[] dst = [0];

     auto n = readN!int(src, dst, 2);

     writeln(dst);
 }
 ---

 If i replace `put` by a cat op (`~`) it works, however the cat 
 op only works here because i test the template with two int[].

 What's wrong ?
Your destination is too small. When arrays are treated as output ranges, they get written to like a buffer. They don't get appended to. If you want to append to them, then use Appender for the output range. On a side note, it's very backwards that you're calling front with parens and popFront without. front is usually a property function (in which case, if property ever gets sorted out properly, front() wouldn't compile), and popFront is never a property function (so you _can_ call it without parens, but it's kind of weird to do so). - Jonathan M Davis
May 04 2015
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 05/04/2015 07:33 AM, Baz wrote:

      int[] src = [1,2,3];
      int[] dst = [0];
In addition to what others said, even if dst had room for two elements, it would lose the newly added element due to a popFront() called implicitly during put()'ting. int[] dst = [0, 0]; // <-- Has room now auto n = readN!int(src, dst, 2); writeln(dst); // <-- Prints "[]" WAT? One solution is to introduce another slice that would not be popFront'ed: int[] dst = [0, 0]; int[] dst2 = dst; // <-- This auto n = readN!int(src, dst, 2); writeln(dst2); // <-- prints "[1, 2]" However, Appender is a better solution. Ali
May 04 2015
parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, 4 May 2015 at 18:50:45 UTC, Ali Çehreli wrote:
 On 05/04/2015 07:33 AM, Baz wrote:

      int[] src = [1,2,3];
      int[] dst = [0];
In addition to what others said, even if dst had room for two elements, it would lose the newly added element due to a popFront() called implicitly during put()'ting. int[] dst = [0, 0]; // <-- Has room now auto n = readN!int(src, dst, 2); writeln(dst); // <-- Prints "[]" WAT? One solution is to introduce another slice that would not be popFront'ed: int[] dst = [0, 0]; int[] dst2 = dst; // <-- This auto n = readN!int(src, dst, 2); writeln(dst2); // <-- prints "[1, 2]" However, Appender is a better solution.
I really think that output ranges need to be rethought through. In most cases, lazy input ranges should be used instead, but they do have their uses. The problem is that they're not designed well enough or thoroughly enough to be very useful outside of Appender. Using arrays as output ranges is particularly bad, but the fact that there is no way to know whether an output range even has room to put a new element or range of elements onto its end makes output ranges unusable in many cases IMHO. - Jonathan M Davis
May 04 2015