digitalmars.D.learn - Odd Associative Array Reference Behavior
- Matt Elkins (23/23) Feb 10 2016 Consider the following definition of Foo and an accompanying
- Steven Schveighoffer (13/35) Feb 10 2016 Misunderstanding.
- Matt Elkins (4/13) Feb 10 2016 Makes sense (though it defies my intuition; I would have expected
Consider the following definition of Foo and an accompanying
unittest:
[code]
struct Foo
{
property int[int] aa() {return m_aa;}
property ref int[int] aaRef() {return m_aa;}
int[int] m_aa;
}
unittest
{
Foo foo;
assert(5 !in foo.m_aa); // Sanity-check to start off
foo.aa[5] = 1; // Add an element with key 5
assert(5 !in foo.m_aa); // ...huh. 5 didn't make it in?
foo.aaRef[5] = 1; // Try again, using the ref variant
assert(5 in foo.m_aa); // Works!
}
[/code]
I was under the impression that associative arrays are reference
types; if I pass a non-ref "copy" of one, shouldn't insertions
still be reflected in the original? Am I dealing with a bug or a
misunderstanding on my part?
Feb 10 2016
On 2/10/16 10:10 PM, Matt Elkins wrote:
Consider the following definition of Foo and an accompanying unittest:
[code]
struct Foo
{
property int[int] aa() {return m_aa;}
property ref int[int] aaRef() {return m_aa;}
int[int] m_aa;
}
unittest
{
Foo foo;
assert(5 !in foo.m_aa); // Sanity-check to start off
foo.aa[5] = 1; // Add an element with key 5
assert(5 !in foo.m_aa); // ...huh. 5 didn't make it in?
foo.aaRef[5] = 1; // Try again, using the ref variant
assert(5 in foo.m_aa); // Works!
}
[/code]
I was under the impression that associative arrays are reference types;
if I pass a non-ref "copy" of one, shouldn't insertions still be
reflected in the original? Am I dealing with a bug or a misunderstanding
on my part?
Misunderstanding.
An AA under the hood is simply a pointer. Initialized to null.
When you pass it around, you are passing a pointer. AA assign checks for
null and allocates a new AA impl to hold the data. But this doesn't
affect other copies (that were null).
So what is happening is aa() returns a null AA. You assign to it, which
allocates a new AA impl, and sets the rvalue to point at it. The rvalue
promptly disappears. The original m_aa is still set to point at null.
If you add more elements, you will see you can do so using the non-ref
version. It's only on the first assignment that the reference changes.
After that, it's the same reference forever (unless reassigned of course).
-Steve
Feb 10 2016
On Thursday, 11 February 2016 at 03:47:09 UTC, Steven Schveighoffer wrote:Misunderstanding. An AA under the hood is simply a pointer. Initialized to null. When you pass it around, you are passing a pointer. AA assign checks for null and allocates a new AA impl to hold the data. But this doesn't affect other copies (that were null). So what is happening is aa() returns a null AA. You assign to it, which allocates a new AA impl, and sets the rvalue to point at it. The rvalue promptly disappears. The original m_aa is still set to point at null.Makes sense (though it defies my intuition; I would have expected an NPE or crash at time of assignment). Thanks!
Feb 10 2016








Matt Elkins <notreal fake.com>