Re: Changing behavior of associative array

2023-12-16 Thread Julian Fondren via Digitalmars-d-learn

On Sunday, 17 December 2023 at 00:10:56 UTC, Kevin Bailey wrote:
instead it seems like 'm' is a pointer to a std::map, that is 
initialized on use if null. (I think it's that latter part that 
gives the illusion of being already initialized.)


Yes: 
https://dlang.org/spec/hash-map.html#construction_and_ref_semantic


Re: Changing behavior of associative array

2023-12-16 Thread Kevin Bailey via Digitalmars-d-learn

On Saturday, 16 December 2023 at 22:44:16 UTC, Dennis wrote:


That's because `m[f] = 1` initializes the associative array to 
something non-null. If you pass a `null` AA to a function which 
adds things, the caller will still have a null pointers. You 
can initialize a non-null empty AA like this:


```D
uint[Foo] m = new uint[Foo];
```

Then, `m` can be passed by value and you can make additions or 
removals which the caller sees, unless you assign a new AA in 
the function.


Thanks Dennis. I'll have to tweak my mental model of what's 
happening. I was picturing a std::map-like thing that was passed 
by reference, but instead it seems like 'm' is a pointer to a 
std::map, that is initialized on use if null. (I think it's that 
latter part that gives the illusion of being already initialized.)




Re: Changing behavior of associative array

2023-12-16 Thread Julian Fondren via Digitalmars-d-learn

On Saturday, 16 December 2023 at 22:44:16 UTC, Dennis wrote:
That's because `m[f] = 1` initializes the associative array to 
something non-null. If you pass a `null` AA to a function which 
adds things, the caller will still have a null pointers.


I've gotten this error in deployed Perl. Whenever the ceremony of 
creating a data structure is reduced, people can lose sight of 
when that happens.


Here's a less common gotcha:

```d
void main() {
import std.stdio : writeln;

int force_realloc(ref int[] seq) {
foreach (int i; 1 .. 1_000_000) {
seq ~= i;
}
return 1234;
}

int[] a = [4321];
writeln(a[0]);  // 4321, of course
a[0] = force_realloc(a);
writeln(a[0]);  // still 4321
}
```

The `a[0]` on the left of the assignment is decided early, and 
then force_realloc() changes what the location should be.


Re: Changing behavior of associative array

2023-12-16 Thread Dennis via Digitalmars-d-learn

On Saturday, 16 December 2023 at 21:30:55 UTC, kdevel wrote:

If you comment out this line

```
//m[f] = 1;
```

in your main function of your posted code you can catch up with 
your

real programm insofar as you now need a ref parameter here, too.


That's because `m[f] = 1` initializes the associative array to 
something non-null. If you pass a `null` AA to a function which 
adds things, the caller will still have a null pointers. You can 
initialize a non-null empty AA like this:


```D
uint[Foo] m = new uint[Foo];
```

Then, `m` can be passed by value and you can make additions or 
removals which the caller sees, unless you assign a new AA in the 
function.


Re: Changing behavior of associative array

2023-12-16 Thread kdevel via Digitalmars-d-learn

On Saturday, 16 December 2023 at 20:04:54 UTC, Kevin Bailey wrote:
I've added a TON of writeln's to confirm this. The *instant* I 
made the parameter "ref", the real program starts acting as 
expected, and the print-outs show the correct results.


If you comment out this line

```
//m[f] = 1;
```

in your main function of your posted code you can catch up with 
your

real programm insofar as you now need a ref parameter here, too.



Does anyone know why the behavior would change? Has anyone seen 
anything like this?


Sure.



Changing behavior of associative array

2023-12-16 Thread Kevin Bailey via Digitalmars-d-learn
Perhaps someone can help solve this mystery. I have a sample 
program that adds structs to an associative array (as keys) in a 
subroutine. The program passes the array by reference as expected 
(below).


My real program does the same thing and yet the associative array 
is passed by value. Thus anything added in the subroutine is lost.


I've added a TON of writeln's to confirm this. The *instant* I 
made the parameter "ref", the real program starts acting as 
expected, and the print-outs show the correct results.


Does anyone know why the behavior would change? Has anyone seen 
anything like this?


I even tried importing the same libraries into both programs. The 
only remaining difference is that the real function has several 
more arguments (7), but I would be shocked if D changed its 
behavior because of that.


thx
```
import std.stdio;

struct Foo
{
uint a, b, c;
}

void add_one_and_recurse(
uint[Foo] m,
int x)
{
if (!x)
return;
foreach (k,v; m) // Prints the 1 from main()
writeln(k, ", ", v); // as expected.
add_one_and_recurse(m, x-1);
Foo f = {4, 5, x};
m[f] = 7;
}

int main()
{
uint[Foo] m;
Foo f = {1, 2, 3};
m[f] = 1;
add_one_and_recurse(m, 3);
foreach (k,v; m) // Prints 4 items
writeln(k, ", ", v); // as expected.
return 0;
}
```