digitalmars.D - error with std.range.put - readN
- Baz (29/29) May 04 2015 the following program fails because of the `put` function :
- sclytrack (27/56) May 04 2015 I believe the put(R,E) calls the doPut(R, E)
- Jonathan M Davis (12/41) May 04 2015 Your destination is too small. When arrays are treated as output
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (14/16) May 04 2015 In addition to what others said, even if dst had room for two elements,
- Jonathan M Davis (10/26) May 04 2015 I really think that output ranges need to be rethought through.
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
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
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
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
On Monday, 4 May 2015 at 18:50:45 UTC, Ali Çehreli wrote:On 05/04/2015 07:33 AM, Baz wrote: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 Davisint[] 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.
May 04 2015