www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - 'auto' with AA

reply David Held <dmd wyntrmute.com> writes:
I would like to do something like this:

Foo[Bar][Baz] nestedAA;
auto innerAA = nestedAA[someBaz];
innerAA[someBar] = someFoo;
assert(someFoo in nestedAA[someBaz]);

Unfortunately, this does not do what I would like, because innerAA 
appears to be a copy rather than a reference.  Is there a nice way to 
tell 'auto' that I want a reference instead?

Dave
Apr 27 2014
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
fOn 04/27/2014 06:00 PM, David Held wrote:

 I would like to do something like this:

 Foo[Bar][Baz] nestedAA;
 auto innerAA = nestedAA[someBaz];
 innerAA[someBar] = someFoo;
 assert(someFoo in nestedAA[someBaz]);
in operator uses a key, not a value. This should work: assert(someBar in nestedAA[someBaz]); Ali
Apr 27 2014
parent reply David Held <dmd wyntrmute.com> writes:
On 4/27/2014 9:32 PM, Ali Çehreli wrote:
 fOn 04/27/2014 06:00 PM, David Held wrote:

  > I would like to do something like this:
  >
  > Foo[Bar][Baz] nestedAA;
  > auto innerAA = nestedAA[someBaz];
  > innerAA[someBar] = someFoo;
  > assert(someFoo in nestedAA[someBaz]);

 in operator uses a key, not a value. This should work:

      assert(someBar in nestedAA[someBaz]);
Sorry, that is what I meant to say. That is, modifying nestedAA through innerAA does not seem to work, which is why I assumed it was a copy. However, I'm pretty sure that if I use auto on an array, I will get a reference: int[][] matrix = [[1, 2, 3, 4]]; auto array = matrix[0]; array[3] = 42; assert(matrix[0][3] == 42); This works just fine. I assumed that AAs were like arrays, and thus, would work like references. Here is a compilable example which fails: void main() { double[int][string] nestedAA; nestedAA["test"] = null; auto innerAA = nestedAA["test"]; innerAA[42] = 3.14; assert(42 in nestedAA["test"]); } Note that I can even assign 'null' to the nested AA, which implies to me that it's a reference type! Now, the problem may be that null is exactly what gets assigned to innerAA. But then, why am I able to happily index it on the very next line? And what exactly does it mean for an AA to be assigned 'null'? This is perfectly legal, but I don't know what it means: double[int] aa = null; It appears to be a NOP, and indistinguishable from: double[int] aa; In fact, this appears to be the source of the problem. If I change the null assignment above to: nestedAA["test"] = [1:1.0]; then everything works as expected, which means that innerAA really is a reference. What is really bizarre is this idea that it starts out as a presumed null reference, and becomes instantiated through use. Note that this is inconsistent with arrays: double[] a = null; a[0] = 3.14; // Range violation I suppose the difference is that naming an invalid key in an AA inserts the key, but naming an invalid index in an array does not. What is peculiar is that the above is a *range violation* and not an *access violation*. It seems to me that the real problem is that a doesn't *refer to an actual array*. So how can an index into 'a' violate its range? The problem I have with the AA solution above is that I have to create some mapping to "instantiate" the nested AA. I thought I would be clever and create a default initializer, like so: nestedAA["test"] = (double[int]).init; Unfortunately, this appears to be equivalent to assigning null, which I assume is the actual value of .init above[1]. Of course, arrays and AAs are "magical" types in D, but it is a little frustrating that an empty initializer is reduced to the null initializer, even though the empty state is not the same as the null state: double[int][string] nestedAA; nestedAA["test"] = null; auto innerAA = nestedAA["test"]; assert(innerAA.length == 0); // empty assert(innerAA is null); // null innerAA[42] = 3.14; assert(innerAA !is null); // not null innerAA.remove(42); assert(innerAA.length == 0); // empty assert(innerAA !is null); // still not null! If there were an initializer which put the AA in the final state above, then I would be happy. I'm sure that .init == null for performance reasons, but I don't see why there isn't some initializer syntax which creates a truly empty-but-not-null state, other than that not enough people needed it. I propose something like: double[int] aa = [void:void]; assert(aa.length == 0); assert(aa !is null); Unfortunately, this is exactly backwards. This *should* be the syntax to make a "null" AA, and .init should make the empty one. But history has prevented that solution. Anything I'm missing? Dave [1] Unfortunately, .init is not documented here: http://dlang.org/hash-map.html even though it is documented for arrays
Apr 28 2014
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/28/2014 12:12 AM, David Held wrote:

  Here is a compilable example which fails:

 void main()
 {
      double[int][string] nestedAA;
      nestedAA["test"] = null;
I think I see what's going on. The line above has almost no effect. For example, it does not populate "test" with an empty double[int] AA. I think there is conceptually an entry but that entry will be created lazily when an element is added to it.
      auto innerAA = nestedAA["test"];
That line is not a reference to "test" but another null: assert(innerAA is null);
      innerAA[42] = 3.14;
That entry populates the local AA. The "test" entry is still null.
      assert(42 in nestedAA["test"]);
And that line fails. Ali
Apr 28 2014