| |
 | Posted by David Held in reply to Ali Çehreli | Permalink Reply |
|
David Held 
Posted in reply to Ali Çehreli
| 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
|