Confusion over what types have value vs reference semantics

Mike Parker via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sun Sep 11 09:10:04 PDT 2016


On Sunday, 11 September 2016 at 15:15:09 UTC, Neurone wrote:
> Hi,
>
> Are there universal rules that I can apply to determine what 
> types have reference or value semantics? I know that for the 
> basic primitive C types (int, bool, etc) has value semantics.

Primitive types (int, bool, etc) and structs are passed by value 
unless a function parameter is annotated with 'ref'.

Classes are reference types, so given instance foo of class Foo, 
foo itself is a reference.

For arrays, it's easiest to think of one as a struct with two 
fields: length and ptr. The ptr field points to the memory where 
the array data is stored. When you pass an array to a function, 
the length & ptr are passed by value (it's a "slice"). That means 
that modifying the length of the array by adding or removing 
elements or attempting to change where ptr is pointing will only 
modify the local copy. You can modify the array elements in the 
original array (manipulate their fields, overwrite them, and 
such), but you can't modify the structure (length or pointer) of 
the original array unless the parameter is annotated with ref.

Although AAs don't have a length or ptr, they work similarly: you 
can modify the contents without ref, but can only modify the 
structure with.

> In particular, I'm still trying to understand  stack vs 
> GC-managed arrays, and slices.

Steven's article on slices should help [1]. It also helps if you 
just think of all dynamic arrays as slices.

int[] foo; // slice with length & ptr, no memory allocated for 
elements
int[3] bar; // static array with length & ptr, three ints 
allocated on the star

The memory for foo needs to be allocated somewhere. It might be 
the GC-managed heap, it might be malloc, it might even be stack 
memory. Doesn't matter.

You cannot modify the length of bar, but you can slice it:

auto barSlice = bar[];

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.

>
> Finally, I have an associative array, and I want to pass it 
> into a function. The function is only reading data. Would 
> putting ref on in function parameter pass it by reference?

You can easily test this:

```
void addElem(int[string] aa, string key, int val) {
     aa[key] = val;
}

void main()
{
     int[string] map;
     map.addElem("key", 10);
     import std.stdio : writeln;
     writeln("The aa was modified: ", ("key" in map) != null);
}
```

AAs behave like arrays. The meta data (like the array length and 
ptr) is passed by value, the data by reference. The above should 
print false. Add ref to the function parameter, it will print 
true. However, if a key already exists in the aa, then you can 
modify it without ref as it isn't changing the structure of the 
aa. The following will print 10 whether the aa parameter is ref 
or not.

```
void addElem(int[string] aa, string key, int val) {
     aa[key] = val;
}

void main()
{
     int[string] map;
     map["key"] = 5;
     map.addElem("key", 10);
     import std.stdio : writeln;
     writeln("The value of key is ", map["key"]);
}
```
[1] https://dlang.org/d-array-article.html




More information about the Digitalmars-d-learn mailing list