Explicit Slicing of std.container.Array

Jonathan M Davis via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sat Jan 24 16:44:58 PST 2015


On Saturday, January 24, 2015 13:11:31 Nordlöw via Digitalmars-d-learn wrote:
> Is there a reason why std.container.Array have to be explicitly
> sliced before being processed by range algorithms such as filter
> typically as
>
>      import std.container: Array;
>      Array!int a;
>      foreach (e; a[].filter!"true") {}
>
> ?
>
> Does memory allocation play a role?
>
> I would like to see it be used in replace of D builtin arrays
> without any code changes.

Dynamic arrays are an odd beast in that they're sort of containers and sort
of not, because they don't really manage their own memory. Either they're a
slice of the stack, manually managed memory, or from GC-allocated memory.
So, really, it's what they're a slice of that manages the memory. And when
you do stuff like ~=, then GC is what takes care of it (possibly
reallocating the memory as GC-allocated memory even if it referred to
manually-allocated memory before). But the dynamic array itself does not. It
doesn't manage memory any more than a pointer does. Just like incrementing a
pointer doesn't involve managing memory, calling popFront on an dynamic
array doesn't manage memory. It just changes exactly which piece of memory
you're looking at. So, a dynamic array can function as a range.

In contrast, an actual container like std.container.Array _does_ manage its
memory. And calling popFront on it would be nonsensical. It's not a range
and shouldn't be one. So, it's just not going to work to expect a container
to function in exactly the same code that a dynamic array does. It would be
closer to expect the range over a container to operate like a dynamic array
does, but even then, that doesn't quite work, because dynamic arrays have
operations which aren't range-based (like ~ and ~=), because they're a weird
special case that's kind of trying to be a container without actually being
a container.

It will work far better if your generic code is written to operate on ranges
or on containers and _not_ dynamic arrays. If it's written to operate on
ranges, then both arrays and a range over a container or any other kind of
range will work with that code, whereas if it's written to work with a
container, then it will work with whatever has the appropriate API - which
_can_ be a dynamic array under a restricted set of operations, but
frequently won't be. Restricting yourself to using [] on the container
_would_ make it work with dynamic arrays, and some functions like remove
might work, but you do have to be a bit careful when trying to use dynamic
arrays and containers interchangebly, because dynamic arrays really aren't
proper containers. Static arrays are actually closer, but they're value
types, whereas containers will normally be reference types, so passing them
around will have different semantics.

Dynamic arrays in D are kind of weird beasts. They're _very_ useful the way
that they are, but their quirkiness can be problematic if you're not
careful, and the fact that they're _sort of_ containers but not is
definitely one place that throws people off.

- Jonathan M Davis




More information about the Digitalmars-d-learn mailing list