On "A New Collections Framework for the Standard Library"
Jack Stouffer via Digitalmars-d
digitalmars-d at puremagic.com
Thu May 18 18:22:50 PDT 2017
On Thursday, 18 May 2017 at 18:27:22 UTC, Andrei Alexandrescu
wrote:
> Iterating over a container using e.g. foreach won't consume the
> container same as iterating over int[] won't consume the slice.
I don't understand why you're mapping the behavior of
ranges/slices, which theoretically are shrinking views of data,
onto containers of data which can grow or shrink. They seem
antithetical to me.
The only reason foreach over a dynamic array doesn't consume the
slice is because foreach uses index based iteration on static and
dynamic arrays and not the std.range.primitives functions.
It's not evident to me that the non-consuming behavior makes
sense to map onto something completely different like containers
that won't even necessarily have index based access.
It seems odd to me that slices would be the design basis when
slices
1. Are intentionally limited in scope design wise to be a
shrinking view of data
2. Only make sense behavior wise for array containers
3. Their ability to grow is a GC oddity which may end up copying
a whole lot of data depending on the origin of the slice
> There is no way to reclaim the original container. If you
> create a container, you get a range positioned to "see" the
> entire container. Once you popFront from that range, you lose
> all access to the first element in the container, unless you
> have a separate copy of the range. This is not new and not
> different from:
>
> auto r = new int[10];
> r.popFront;
>
> What happens here is an array of 10 elements gets created. But
> you don't get a type "array of 10 integers". You get "a slice
> of integers, incidentally initialized to refer to the entire
> array of 10 integers that was just created". Next, you decide
> you don't care about the first element in the array. Once you
> call r.popFront, access to that element is lost forever.
First off, how are you going to do something like a map over a
immutable container then, as map uses the range primitives and
not foreach? There's no reason in principal that that should
cause an issue. But with that design popFront is mutating the
underlying data, and therefore should not be allowed. But this
works with the std.container design because popFront is mutating
the range view which has no reason to be immutable.
Secondly, if I want to say, perform a map over the elements of a
container for some output, and I want to do things with the
elements later in the code, then I have to create a copy of the
container and pass the original to map? If that's the case then
why not just go with the std.container behavior of getting a
range from a primitive if you end up having to create range
copies? I mean it's fundamentally the same, but that way you
don't have to worry about the copies changing the data of the
container out from under you.
What happens to the copy of a container when the original
modifies the underlying data? For example, what should this code
print?
auto container = Array!int(MAllocator.instance);
container.put(iota(10));
auto container_copy = container;
container.popBackN(5);
container.insertBack(1);
container_copy.each!(a => write(a, ", "));
In my estimation, a properly designed containers library should
print
0, 1, 2, 3, 4, 1, 5, 6, 7, 8, 9
But from what you're describing, that the containers act like
slices, the code with print
0, 1, 2, 3, 4, 1, 6, 7, 8, 9
More information about the Digitalmars-d
mailing list