std.range's put on arrays needs to change
Steven Schveighoffer
schveiguy at gmail.com
Sun Jun 26 12:57:15 UTC 2022
On 6/25/22 7:44 PM, WebFreak001 wrote:
> let's see this code:
>
> ```d
> 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](https://dlang.org/phobos/std_range_primitives.html#put):
>
> ```d
> 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:
>
> ```d
> 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`.
It might not be expected, but to disable allowing reference input ranges
as output ranges would break so many fundamental usages, such as
`std.algorithm.copy`. You wouldn't just be disabling slices, it would be
a complete removal of a whole class of output ranges.
What we need is an appendTo wrapper:
```d
struct AppendTo(T)
{
private T[] *arr;
this(return T[]* arr) { this.arr = arr; }
void put(X)(X val) if (__traits(compiles, (*arr) ~= val)) {
(*arr) ~= val;
}
}
auto appendTo(T)(return ref T[] arr)
{
return AppendTo!T(&arr);
}
```
-Steve
More information about the Digitalmars-d
mailing list