Passing dynamic arrays
Jonathan M Davis
jmdavisProg at gmx.com
Mon Nov 8 17:08:32 PST 2010
On Monday, November 08, 2010 13:54:28 spir wrote:
> On Mon, 08 Nov 2010 15:32:56 -0500
>
> Jesse Phillips <jessekphillips+D at gmail.com> wrote:
> > But they are past by reference. You can modify the data all you want, but
> > cannot reassign the reference itself.
>
> No, they are _not_ passed by reference. Stop saying that, this is precisely
> what causes confusion. This is reference semantics:
As Jesse says, they _are_ passed by reference. The struct itself _is_ the
reference. What makes arrays odd is that anything that resizes it returns a
_new_ reference or alters the current one. So, using ~= or length can result in
a reference with a new ptr value and a new length value, and the reference then
refers to a different block of memory. In the case of an object reference, you
could implement ~= to return a new reference in exactly the same manner and get
behavior similar to an array, but no one does that normally.
_Everything_ which is not passed as ref or out is passed by value in D. And
technically, ref and out probably wrap the value being passed in a pointer and
that pointer is passed by value. Really, this is easier to understand when
dealing with pointers than references, since references hide the dereferencing
process. Take this program for instance:
import std.stdio;
void func1(int* b)
{
*b = 12;
}
void func2(int* c)
{
c = new int;
*c = 7;
}
void func3(int** d)
{
*d = new int;
**d = 3;
}
void main()
{
int* i = new int;
int* j = i;
*i = 5;
writefln("%s %s", *i, *j);
func1(i);
writefln("%s %s", *i, *j);
func2(i);
writefln("%s %s", *i, *j);
func3(&i);
writefln("%s %s", *i, *j);
}
It prints out
5 5
12 12
12 12
3 12
i and j both point to the same memory, so when that memory is altered, the value
that you get when you dereference them is altered. When func1() is called, the
value of i is passed to func1() - that is the address that i points to - so b
points to the same memory that i and j do, so altering the value in that memory,
alters the memory for all three pointers.
When calling func2(), c is a copy of i and holds the same address. However,
setting c to a new address means that it no longer points to the same memory and
any changes made to the memory that it points to does not alter the memory that
i and j point to. So, they still print out the same value when dereferenced.
func3() takes the address of i. That means that d the holds the address of i and
can alter i itself rather than just the memory that it points to. c points to
the memory that holds i itself. So, when assigning the dereferenced c to a new
address, i itself receives a new address. Then when altering the memory that's
pointed to by the address that c holds, you alter the memory that i points to
and change that value. However, while j held the same address as i originally
and altering the memory at that address therefore altered what both i and j
pointed to, once i was given a new address by c, they i and j held different
addresses and altering the memory that one pointed to did not alter the one that
the other pointed to.
I expect that you've gone over this sort of thing before, but you need to
realize that references are _exactly_ the same. The only difference is the lack
of dereferencing step when accessing what it points to. So, whether you're
passing object reference or an array reference, you're passing that reference by
value, and any changes to the copy won't change the original. Changes to what
the reference refers to _will_ change what the original reference points to as
well since they point to the same thing, but changes to the copied reference
won't change the original. So, if make the copied reference point to something
else, then it won't change what the original reference pointed to anymore.
Having an array that you use ~= on is like doing objRef = new Foo(); on a
reference that was passed into the function. It now points to something else, so
it's not going to affect the original. What gets somewhat weird about it is that
~= doesn't necessarily return a new reference, and if it doesn't then the length
is different, so it still hasn't affected the original reference (if it was going
to, it would have resulted in a reallocation). The value of the copied reference
has changed.
I grant you that if you're expecting ~= to return the same reference every time
and thereby somehow alter the original reference, then you're going to be
surprised. But it's completely consistent with how pointers and references work.
You can alter the memory that they point to, but since the pointer or reference
itself was passed by value, altering it will not alter the original.
- Jonathan M Davis
More information about the Digitalmars-d
mailing list