www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - std.array.put doesn't put

reply Paul D. Anderson <paul.d.removethis.anderson comcast.andthis.net> writes:
I've entered this as a Phobos bug, but wanted to be sure I was understanding
this properly (i.e., this is a bug, right?):

From the description of the put primitive in std.range:

"r.put(e) puts e in the range (in a range-dependent manner) and advances to the
popFront position in the range. Successive calls to r.put add elements to the
range. put may throw to signal failure."

From the example of std.array for the put function:

void main()
{
    int[] a = [ 1, 2, 3 ];
    int[] b = a;
    a.put(5);
    assert(a == [ 2, 3 ]);
    assert(b == [ 5, 2, 3 ]);
}

So, "putting" 5 into the array a removes the first element in a, and changes
the value of the first element of b. I would expect the first assert in the
code above to read:

    assert(a == [ 5, 1, 2, 3 ]);

The implementation of std.array.put doesn't make sense: 

void put(T, E)(ref T[] a, E e) { assert(a.length); a[0] = e; a = a[1 .. $]; }

It modifies a[0] and then replaces the array with the tail of the array,
omitting the first element.

It's possible there is some arcane meaning to the word "put" that I'm not aware
of, but if it means "insert an element at the front of the range" then
std.array.put is wrongly implemented.

Paul
Mar 01 2010
parent reply "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
Paul D. Anderson wrote:
 I've entered this as a Phobos bug, but wanted to be sure I was understanding
this properly (i.e., this is a bug, right?):
 
 From the description of the put primitive in std.range:
 
 "r.put(e) puts e in the range (in a range-dependent manner) and advances to
the popFront position in the range. Successive calls to r.put add elements to
the range. put may throw to signal failure."
 
 From the example of std.array for the put function:
 
 void main()
 {
     int[] a = [ 1, 2, 3 ];
     int[] b = a;
     a.put(5);
     assert(a == [ 2, 3 ]);
     assert(b == [ 5, 2, 3 ]);
 }
 
 So, "putting" 5 into the array a removes the first element in a, and changes
the value of the first element of b. I would expect the first assert in the
code above to read:
 
     assert(a == [ 5, 1, 2, 3 ]);
 
 The implementation of std.array.put doesn't make sense: 
 
 void put(T, E)(ref T[] a, E e) { assert(a.length); a[0] = e; a = a[1 .. $]; }
 
 It modifies a[0] and then replaces the array with the tail of the array,
 omitting the first element.
 
 It's possible there is some arcane meaning to the word "put" that I'm not
aware of, but if it means "insert an element at the front of the range" then
std.array.put is wrongly implemented.
 
 Paul

I don't think it's a bug, I think it's just that arrays aren't that useful as output ranges. It has to be defined that way for it to adhere to the range interface conventions. (Think of the array as a file instead, then it makes more sense.) You just have to keep a backup slice of the entire array so you can access the elements you have put() later: int[] a = [0, 0, 0, 0, 0, 0]; int[] aSlice = a[]; foreach (i; 0 .. a.length) aSlice.put(i); assert (a == [0, 1, 2, 3, 4, 5]); -Lars
Mar 01 2010
next sibling parent "Robert Jacques" <sandford jhu.edu> writes:
On Mon, 01 Mar 2010 16:51:41 -0500, Lars T. Kyllingstad  
<public kyllingen.nospamnet> wrote:
 Paul D. Anderson wrote:
 I've entered this as a Phobos bug, but wanted to be sure I was  
 understanding this properly (i.e., this is a bug, right?):
  From the description of the put primitive in std.range:
  "r.put(e) puts e in the range (in a range-dependent manner) and  
 advances to the popFront position in the range. Successive calls to  
 r.put add elements to the range. put may throw to signal failure."
  From the example of std.array for the put function:
  void main()
 {
     int[] a = [ 1, 2, 3 ];
     int[] b = a;
     a.put(5);
     assert(a == [ 2, 3 ]);
     assert(b == [ 5, 2, 3 ]);
 }
  So, "putting" 5 into the array a removes the first element in a, and  
 changes the value of the first element of b. I would expect the first  
 assert in the code above to read:
      assert(a == [ 5, 1, 2, 3 ]);
  The implementation of std.array.put doesn't make sense:  void put(T,  
 E)(ref T[] a, E e) { assert(a.length); a[0] = e; a = a[1 .. $]; }
  It modifies a[0] and then replaces the array with the tail of the  
 array,
 omitting the first element.
  It's possible there is some arcane meaning to the word "put" that I'm  
 not aware of, but if it means "insert an element at the front of the  
 range" then std.array.put is wrongly implemented.
  Paul

I don't think it's a bug, I think it's just that arrays aren't that useful as output ranges. It has to be defined that way for it to adhere to the range interface conventions. (Think of the array as a file instead, then it makes more sense.) You just have to keep a backup slice of the entire array so you can access the elements you have put() later: int[] a = [0, 0, 0, 0, 0, 0]; int[] aSlice = a[]; foreach (i; 0 .. a.length) aSlice.put(i); assert (a == [0, 1, 2, 3, 4, 5]); -Lars

Yes, it's not a bug. If you think of a common usage of arrays (buffers) this makes perfect sense. And if you want the other behavior you're supposed to use the appender wrapper.
Mar 01 2010
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
--000325559052c4419c0480d12498
Content-Type: text/plain; charset=ISO-8859-1

On Mon, Mar 1, 2010 at 22:51, Lars T. Kyllingstad
<public kyllingen.nospamnet> wrote:

 Paul D. Anderson wrote:

  "r.put(e) puts e in the range (in a range-dependent manner) and advances
 to the popFront position in the range. Successive calls to r.put add
 elements to the range. put may throw to signal failure."


 It modifies a[0] and then replaces the array with the tail of the array,
 omitting the first element.


I had the same reaction when reading array.put for the first time. How can a function putting values in something make them non-accessible at the same time? But that's because for arrays the container and the associated range (view) are the same, leading to some confusion. put puts values not in the range as said in std.range but in the container accessed by the range. The range itself updates in the only way a range can: by shrinking (so, popFront), giving you a new place to put a another value. As Lars said, a classical use would be: Container c = new Container(values); auto view =c.asOutputRange(); // view is an output range. Andrei suggested '.all' as a property returning a range on all values. foreach(elem; view) view.put(someOtherValues); // writes values in c, consumes view. assert(view.empty); // Now view is exhausted and c contains someOtherValues.
 It's possible there is some arcane meaning to the word "put" that I'm not
 aware of, but if it means "insert an element at the front of the range" then
 std.array.put is wrongly implemented.


range.front = someValue; But then, how would you go putting some more? You cannot extend a range, I think. You can create a new range chaining new values and the old range, but that creates a new one. auto prepended = chain(newValues, oldValues); I think I have somewhere something inspired by zippers ( http://en.wikipedia.org/wiki/Zipper_%28data_structure%29), where a range 'remembers' previous values (stores them in an array) and you can make the front retreat, giving access to old values anew. But it cannot modify the sublying container, only the values stored (artificially) in the range. It's useful for some algorithms that need to go back and forth on a few positions. Philippe --000325559052c4419c0480d12498 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <div class=3D"gmail_quote">On Mon, Mar 1, 2010 at 22:51, Lars T. Kyllingsta= d <span dir=3D"ltr">&lt;public kyllingen.nospamnet&gt;</span> wrote:<br><bl= ockquote class=3D"gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; border-l= eft: 1px solid rgb(204, 204, 204); padding-left: 1ex;"> <div><div></div><div class=3D"h5">Paul D. Anderson wrote:<br></div></div></= blockquote><div>from std.range <br></div><blockquote class=3D"gmail_quote" = style=3D"margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 20= 4); padding-left: 1ex;"> <div><div class=3D"h5"> <blockquote class=3D"gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; borde= r-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;"> &quot;r.put(e) puts e in the range (in a range-dependent manner) and advanc= es to the popFront position in the range. Successive calls to r.put add ele= ments to the range. put may throw to signal failure.&quot;<br> </blockquote></div></div></blockquote><div>=A0with std.array.put:</div><blo= ckquote class=3D"gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; border-le= ft: 1px solid rgb(204, 204, 204); padding-left: 1ex;"><div><div class=3D"h5= "><blockquote class=3D"gmail_quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; bor= der-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;"> It modifies a[0] and then replaces the array with the tail of the array,<br=

br>It seems to me array.put does what the description in std.range entails.= <br><br>I had the same reaction when reading array.put for the first time. = How can a function putting values in something make them non-accessible at = the same=20 time? But that&#39;s because for arrays the container and the associated ra= nge (view) are the same, leading to some confusion. put puts values not in = the range as said in std.range but in the container accessed by the range. = The range itself updates in the only way a range can: by shrinking (so, pop= Front), giving you a new place to put a another value.<br> <br>As Lars said, a classical use would be:<br><br>Container c =3D new Cont= ainer(values);<br>auto view =3Dc.asOutputRange(); // view is an output rang= e. Andrei suggested &#39;.all&#39; as a property returning a range on all v= alues. <br> <br>foreach(elem; view) view.put(someOtherValues); // writes values in c, c= onsumes view.<br>assert(view.empty); // Now view is exhausted and c contain= s someOtherValues.<br><br><br></div><blockquote class=3D"gmail_quote" style= =3D"margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); p= adding-left: 1ex;"> <div><div class=3D"h5"><blockquote class=3D"gmail_quote" style=3D"margin: 0= pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: = 1ex;"> <br> It&#39;s possible there is some arcane meaning to the word &quot;put&quot; = that I&#39;m not aware of, but if it means &quot;insert an element at the f= ront of the range&quot; then std.array.put is wrongly implemented.<br> <br></blockquote></div></div></blockquote><div><br>For some ranges, you can= replace the front value:<br><br> range.front =3D someValue;<br><br>But then, how would you go putting some m= ore?<br>You cannot extend a range, I think. You can create a new range chai= ning new values and the old range, but that creates a new one.<br>auto prep= ended =3D chain(newValues, oldValues);<br> <br>I think I have somewhere something inspired by zippers (<a href=3D"http= ://en.wikipedia.org/wiki/Zipper_%28data_structure%29">http://en.wikipedia.o= rg/wiki/Zipper_%28data_structure%29</a>), where a range &#39;remembers&#39;= previous values (stores them in an array) and you can make the front retre= at, giving access to old values anew. But it cannot modify the sublying con= tainer, only the values stored (artificially) in the range. It&#39;s useful= for some algorithms that need to go back and forth on a few positions.<br> <br><br>Philippe<br><br><br></div></div> --000325559052c4419c0480d12498--
Mar 02 2010
prev sibling next sibling parent Paul D. Anderson <paul.d.removethis.anderson comcast.andthis.net> writes:
Lars T. Kyllingstad Wrote:

 Paul D. Anderson wrote:
 I've entered this as a Phobos bug, but wanted to be sure I was understanding
this properly (i.e., this is a bug, right?):
 
 From the description of the put primitive in std.range:
 
 "r.put(e) puts e in the range (in a range-dependent manner) and advances to
the popFront position in the range. Successive calls to r.put add elements to
the range. put may throw to signal failure."
 
 From the example of std.array for the put function:
 
 void main()
 {
     int[] a = [ 1, 2, 3 ];
     int[] b = a;
     a.put(5);
     assert(a == [ 2, 3 ]);
     assert(b == [ 5, 2, 3 ]);
 }
 
 So, "putting" 5 into the array a removes the first element in a, and changes
the value of the first element of b. I would expect the first assert in the
code above to read:
 
     assert(a == [ 5, 1, 2, 3 ]);
 
 The implementation of std.array.put doesn't make sense: 
 
 void put(T, E)(ref T[] a, E e) { assert(a.length); a[0] = e; a = a[1 .. $]; }
 
 It modifies a[0] and then replaces the array with the tail of the array,
 omitting the first element.
 
 It's possible there is some arcane meaning to the word "put" that I'm not
aware of, but if it means "insert an element at the front of the range" then
std.array.put is wrongly implemented.
 
 Paul

I don't think it's a bug, I think it's just that arrays aren't that useful as output ranges. It has to be defined that way for it to adhere to the range interface conventions. (Think of the array as a file instead, then it makes more sense.) You just have to keep a backup slice of the entire array so you can access the elements you have put() later: int[] a = [0, 0, 0, 0, 0, 0]; int[] aSlice = a[]; foreach (i; 0 .. a.length) aSlice.put(i); assert (a == [0, 1, 2, 3, 4, 5]); -Lars

Thanks (to all) for the clarification. I was wondering how such a big mistake could go unnoticed. :-) I will check into a range re-education camp until my mind is enlightened. Paul
Mar 02 2010
prev sibling next sibling parent Steve Teale <steve.teale britseyeview.com> writes:
 
 I will check into a range re-education camp until my mind is
 enlightened.
 
 Paul

That's exactly how I felt when I discovered this gem of clarity and Andrei enlightened me. Steve
Mar 02 2010
prev sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
--001636833958c278160480e9ff33
Content-Type: text/plain; charset=ISO-8859-1

On Wed, Mar 3, 2010 at 06:52, Steve Teale <steve.teale britseyeview.com>wrote:

 I will check into a range re-education camp until my mind is
 enlightened.

 Paul

That's exactly how I felt when I discovered this gem of clarity and Andrei enlightened me.

--001636833958c278160480e9ff33 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <br><br><div class=3D"gmail_quote">On Wed, Mar 3, 2010 at 06:52, Steve Teal= e <span dir=3D"ltr">&lt;<a href=3D"mailto:steve.teale britseyeview.com">ste= ve.teale britseyeview.com</a>&gt;</span> wrote:<br><blockquote class=3D"gma= il_quote" style=3D"margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(20= 4, 204, 204); padding-left: 1ex;"> <div class=3D"im">&gt;<br> &gt; I will check into a range re-education camp until my mind is<br> &gt; enlightened.<br> &gt;<br> &gt; Paul<br> <br> </div>That&#39;s exactly how I felt when I discovered this gem of clarity a= nd<br> Andrei enlightened me.<br> <font color=3D"#888888"><br></font></blockquote><div><br>Now, repeat after = me: retro is a good name, retro is a good name... <br></div></div><br> --001636833958c278160480e9ff33--
Mar 03 2010