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


Reply via email to