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:
On Mon, Mar 1, 2010 at 22:51, Lars T. Kyllingstad
<public kyllingen.nospamnet> wrote:

 Paul D. Anderson wrote:
from 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."
with std.array.put:
 It modifies a[0] and then replaces the array with the tail of the array,
 omitting the first element.
It seems to me array.put does what the description in std.range entails. 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.
For some ranges, you can replace the front value: 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
Mar 02 2010
prev sibling parent reply 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
parent reply 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
parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
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.
Now, repeat after me: retro is a good name, retro is a good name...
Mar 03 2010