Confusion over what types have value vs reference semantics

Jonathan M Davis via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Tue Sep 13 08:44:23 PDT 2016


On Tuesday, September 13, 2016 15:27:07 Neurone via Digitalmars-d-learn wrote:
> On Sunday, 11 September 2016 at 16:14:59 UTC, Mike Parker wrote:
> > On Sunday, 11 September 2016 at 16:10:04 UTC, Mike Parker wrote:
> >> And here, no memory is allocated. barSlice.ptr is the same as
> >> bar.ptr and barSlice.length is the same as bar.length.
> >> However, if you append a new element:
> >>
> >> barSlice ~= 10;
> >>
> >> The GC will allocate memory for a new array and barSlice will
> >> no longer point to bar. It will now have four elements.
> >
> > I should clarify that this holds true for all slices, not just
> > slices of static arrays. The key point is that appending to a
> > slice will only allocate if the the .capacity property of the
> > slice is 0. Slices of static arrays will always have a capacity
> > of 0. Slices of slices might not, i.e. there may be room in the
> > memory block for more elements.
>
> Thanks for the detailed answer. I still don't get the advantage
> of passing slices into functions by value allowing modification
> to elements of the original array.  Is there an way to specify
> that a true independent copy of an array should be passed into
> the function? E.g, in c++ func(Vector<int> v) causes a copy of
> the argument to be passed in.

Slices are a huge performance boost (e.g. the fact that we have slicing like
this for strings makes parsing code _way_ more efficient by default than
would ever be the case for something like std::string). If you're worried
about a function mutating the elements of an array that it's given, then you
can always mark them with const. e.g.

auto foo(const(int)[] arr) {...}

But there is no way to force a naked dynamic array to do a deeper copy when
passed. If you're worried about it, you can explicitly call dup to create a
copy of the array rather than slice it - e.g. foo(arr.dup) - but the
function itself can't enforce that behavior. The closest that it could do
would be to explicitly dup the parameter itself - though if you were going
to do that, you'd want to make it clear in the documentation, since that's
not a typical thing to do, and if someone wanted to ensure that an array
that they were passing to the function didn't get mutated, they'd dup it
themselves, which would result in two dups if your function did the dup.

If you want a dynamic array to be duped every time it's passed to a function
or otherwise copied, you'd need to create a wrapper struct with a postblit
constructor that called dup. That would generally make for unnecessarily
inefficient code though. The few containers in std.container are all
reference types for the same reason - containers which copy by default make
it way too easy to accidentally copy them and are arguably a bad default
(though obviously, there are cases where that would be the best behavior).

So, the typical thing to do with dynamic arrays is to use const or immutable
elements when you want to ensure that they don't get mutated when passing
them around and duping or iduping a dynamic array when you want to ensure
that you have a copy of the array rather than a slice.

- Jonathan M Davis



More information about the Digitalmars-d-learn mailing list