Allocating an empty non null associative arary

WebFreak001 d.forum at webfreak.org
Tue Mar 31 06:51:16 UTC 2020


On Tuesday, 31 March 2020 at 02:51:11 UTC, Superstar64 wrote:
> I want to be modify an associative array by reference from 
> another function. However null associative arrays are pass by 
> value. How do I generically create an empty associative array?
> ---
> import std.stdio;
>
>
> void addElement(int[int] data){
> 	data[0] = 0;
> }
>
> void nonempty() {
> 	int[int] items = [1 : 1];
> 	writeln(items); // [1 : 1]
> 	addElement(items);
> 	writeln(items); // [0 : 0, 1 : 1]
> }
>
> void empty(){
> 	int[int] items = null;
> 	writeln(items); // []
> 	addElement(items);
> 	writeln(items); // []
> }
>
> void main(){
> 	nonempty();
> 	empty();
> }
> ---

This doesn't only happen with null, you will notice that that 
function will eventually not add anything if you only add values. 
This is because by adding values you might reallocate the map at 
some other place in memory and because it's not ref, the caller 
won't have the map point to the new reference and still only have 
the old data.

Setting an existing key shouldn't reallocate, though it's not 
exactly specified but it hints towards it: 
https://dlang.org/spec/hash-map.html#construction_assignment_entries

So basically if you plan to add or remove items from your map, it 
could reallocate your memory, so you need to pass your argument 
by ref, so it updates the caller reference.

// use when inserting or updating
void addElement(scope ref int[int] data) {
	data[0] = 1;
}

// use only when updating existing keys (though you might also 
consider using ref anyway)
void changeElement(scope int[int] data) {
	data[0] = 2;
}

// use for only reading
int readElement(scope const int[int] data) {
	return data[0];
}

The ref signals the caller that the passed in data will be 
modified. It's like passing pointers, but the value cannot be 
null.

The scope signals the caller that you don't escape the reference 
outside the function, so you can be sure the memory won't be 
altered after the function has finished. This is especially 
enforced if you pass -dip1000.

The const signals the caller that you won't modify the data. If 
you use const, you need to be very strict with it and use it in 
all your functions consistently, also adding const (or preferably 
inout) to member functions of structs and classes not modifying 
their data. (like getters) - You might otherwise need to do ugly 
casts to remove the const to hack around a function definition 
which might break the correctness of your program. But if you can 
do const for your parameters, definitely add it.

The attributes are both for good documentation but also to 
enforce correct usage by the compiler.


More information about the Digitalmars-d-learn mailing list