Jump to page: 1 2
Thread overview
std.range's put on arrays needs to change
Jun 25, 2022
WebFreak001
Jun 26, 2022
Basile B.
Jun 26, 2022
Paul Backus
Jun 26, 2022
H. S. Teoh
Jun 26, 2022
Paul Backus
Jun 26, 2022
Sebastiaan Koppe
Jun 26, 2022
Kostiantyn Tokar
Jun 26, 2022
Kostiantyn Tokar
Jun 26, 2022
H. S. Teoh
Jun 26, 2022
Kostiantyn Tokar
Jun 26, 2022
WebFreak001
Jun 26, 2022
Kostiantyn Tokar
June 25, 2022

let's see this code:

import std.range;

int[] arr;
arr.put(2);

someone not coming from a D backround (or even those coming from it) might expect here to have arr be equal to [2] afterwards.

However this is not the case:

core.exception.AssertError@/dlang/dmd/linux/bin64/../../src/phobos/std/range/primitives.d(2472): Attempting to fetch the front of an empty array of int
----------------
??:? _d_assert_msg [0x563cbe9c3360]
/dlang/dmd/linux/bin64/../../src/phobos/std/range/primitives.d:2472 pure nothrow ref @property @nogc @safe inout(int) std.range.primitives.front!(int).front(return scope inout(int)[]) [0x563cbe9a0fe3]
/dlang/dmd/linux/bin64/../../src/phobos/std/range/primitives.d:297 pure nothrow @nogc @safe void std.range.primitives.doPut!(int[], int).doPut(ref int[], ref int) [0x563cbe9a0f62]
/dlang/dmd/linux/bin64/../../src/phobos/std/range/primitives.d:380 pure nothrow @nogc @safe void std.range.primitives.put!(int[], int).put(ref int[], int) [0x563cbe9a0f37]
./onlineapp.d:8 _Dmain [0x563cbe9a0ee1]

this is because put is there to write into a pre-allocated buffer if you pass in an array, as it assumes it is a slice:

int[3] buffer;
auto slice = buffer[];
put(slice, 1);
put(slice, 2);
put(slice, 3);
assert(!slice.length);
assert(buffer == [1,2,3]);

which seems to be the way this is intended to be used.

However now I argue this is very unintuitive behavior, especially when you compare it to appender!int:

auto arr = appender!(int[]);
arr.put(1);
assert(arr.data == [1]);

put on an appender actually adds to the array, the appender allocates memory for it.

I strongly feel that this behavior is very inconsistent and unexpected for most users and should be changed. I think we should deprecate simple arrays/slices on put and rename the method for those.

I propose put with slices should be renamed to putInto.

June 26, 2022

On Saturday, 25 June 2022 at 23:44:59 UTC, WebFreak001 wrote:

>

let's see this code:
[...]
I strongly feel that this behavior is very inconsistent and unexpected for most users and should be changed.

I think nobody can disagree. A bit of archeology shows that's it's a very recurring topic:

Deprecating the problematic behavior should not be a problem. Since on dynamic arrays put() does not do what people think it does, people dont use it.

June 26, 2022

On Saturday, 25 June 2022 at 23:44:59 UTC, WebFreak001 wrote:

>

I strongly feel that this behavior is very inconsistent and unexpected for most users and should be changed. I think we should deprecate simple arrays/slices on put and rename the method for those.

I propose put with slices should be renamed to putInto.

I agree that put on arrays does not do what you usually want it to do, but I do not agree that it is inconsistent. It is exactly the same behavior you would get if you used the input range interface and wrote arr.front = 2; arr.popFront;.

The bigger problem is that unlike an input range's empty method, there is no generic way to tell if an output range is full before you try to put something into it. And, since put fails with an Error rather than an Exception, you cannot handle failure after the fact either--the only thing you can do is crash.

IMO put should be changed in std.v2 to either throw an exception or return false when attempting to insert an element into a full output range.

June 25, 2022
On Sun, Jun 26, 2022 at 04:21:46AM +0000, Paul Backus via Digitalmars-d wrote:
> On Saturday, 25 June 2022 at 23:44:59 UTC, WebFreak001 wrote:
> > I strongly feel that this behavior is very inconsistent and unexpected for most users and should be changed. I think we should deprecate simple arrays/slices on `put` and rename the method for those.
> > 
> > I propose put with slices should be renamed to `putInto`.
> 
> I agree that `put` on arrays does not do what you usually want it to do, but I do not agree that it is inconsistent. It is exactly the same behavior you would get if you used the input range interface and wrote `arr.front = 2; arr.popFront;`.

Yeah, it's consistent where calling put multiple times writes to consecutive locations in the original array.


[...]
> IMO `put` should be changed in `std.v2` to either throw an exception or return `false` when attempting to insert an element into a full output range.

Why the needlessly complex workaround? Just introduce a .full method, the natural analogue of .empty for output ranges.


T

-- 
Public parking: euphemism for paid parking. -- Flora
June 26, 2022

On Saturday, 25 June 2022 at 23:44:59 UTC, WebFreak001 wrote:

>

I strongly feel that this behavior is very inconsistent and unexpected for most users and should be changed. I think we should deprecate simple arrays/slices on put and rename the method for those.

I propose put with slices should be renamed to putInto.

What should I do if I want to preallocate a slice and copy some input range into it? I wouldn't be able to use std.algorithm.copy for this simple purpose, because it uses put internally.

BTW, isn't it a breaking change? It changes semantics of put into a slice, and it wouldn't be available in a @nogc context.

I don't like special casing of slices from all other output ranges. Basically you need to provide analogues for putInto of isOutputRange and all standard functions that use put, like std.algorithm.copy, for this sole reason.

So why to change this if std.array.appender exists?

June 26, 2022

On Sunday, 26 June 2022 at 06:33:13 UTC, Kostiantyn Tokar wrote:

>

I don't like special casing of slices from all other output ranges. Basically you need to provide analogues for putInto of isOutputRange and all standard functions that use put, like std.algorithm.copy, for this sole reason.

Should have said "special casing of putInto from put".

June 26, 2022
On Sun, Jun 26, 2022 at 06:33:13AM +0000, Kostiantyn Tokar via Digitalmars-d wrote: [...]
> What should I do if I want to preallocate a slice and copy some input range into it? I wouldn't be able to use `std.algorithm.copy` for this simple purpose, because it uses `put` internally.

Just take a slice of it with [].


T

-- 
A computer doesn't mind if its programs are put to purposes that don't match their names. -- D. Knuth
June 26, 2022

On Sunday, 26 June 2022 at 10:29:17 UTC, H. S. Teoh wrote:

>

On Sun, Jun 26, 2022 at 06:33:13AM +0000, Kostiantyn Tokar via Digitalmars-d wrote: [...]

>

What should I do if I want to preallocate a slice and copy some input range into it? I wouldn't be able to use std.algorithm.copy for this simple purpose, because it uses put internally.

Just take a slice of it with [].

T

I'm talking about suggestion. IIUC, with suggested change put will be appending to the slice. And it wouldn't work with @nogc.

June 26, 2022

Sorry, I misunderstood. For some reason I thought that put is suggested to append to a slice, like put with appender. But anyway, I still want to ask the question about functions that use put internally.

On Saturday, 25 June 2022 at 23:44:59 UTC, WebFreak001 wrote:

>

I strongly feel that this behavior is very inconsistent and unexpected for most users and should be changed. I think we should deprecate simple arrays/slices on put and rename the method for those.

I propose put with slices should be renamed to putInto.

To put it into a context, consider the following code:

void main() @nogc
{
    import std : iota, copy, save;
    import core.stdc.stdlib : malloc;
    auto n = 5;
    auto buffer = (cast(int*) malloc(n * int.sizeof))[0..n];
    n.iota.copy(buffer.save);
}

Currently this code fills the buffer, allocated by malloc, with the elements of iota.

Now, assuming the suggested change is implemented, how do I replicate the current behaviour after the deprecation period? Iterate over iota and call putInto directly?

June 26, 2022
On Sunday, 26 June 2022 at 05:10:50 UTC, H. S. Teoh wrote:
> On Sun, Jun 26, 2022 at 04:21:46AM +0000, Paul Backus via Digitalmars-d wrote:
>> IMO `put` should be changed in `std.v2` to either throw an exception or return `false` when attempting to insert an element into a full output range.
>
> Why the needlessly complex workaround? Just introduce a .full method, the natural analogue of .empty for output ranges.

How would you implement .full for, say, an output range that writes to a file?
« First   ‹ Prev
1 2