March 13, 2014
On Wednesday, 12 March 2014 at 06:53:19 UTC, monarch_dodra wrote:
> I *believe* it's really just that you are allowed to *initialize* a static array (of any depth) from a dynamic array.
>
> However, for assignment, it doesn't work that way:
>
>     int[] a = [0, 1, 2, 3];
>     int[2][1][2][1] b = a; //OK!
>     b = a; //ERROR

Is this intentional, or is it a bug?
March 14, 2014
On Thursday, 13 March 2014 at 18:17:03 UTC, Chris Williams wrote:
> On Thursday, 13 March 2014 at 03:31:09 UTC, ed wrote:
>> On Thursday, 13 March 2014 at 00:15:19 UTC, Chris Williams wrote:
>> [snip]
>>> It shouldn't and probably isn't working.
>>
>> It is working and in fact it is in a "const pure @safe" function. So I will trust it  :-)
>
> Well it's like a broken watch being correct twice a day. The correct result doesn't mean that something is working.

But this is perfectly valid and safe D code, is it not?

long[4] a=[1,2,3,4];
int[2][2] b = a.to!(int[]);

which is no different to this:

int[] a_int = a.to!(int[]);
int[2][2] b = a_int;

Am I missing something here?

Thanks,
ed






March 14, 2014
On Friday, 14 March 2014 at 04:18:18 UTC, ed wrote:
> On Thursday, 13 March 2014 at 18:17:03 UTC, Chris Williams wrote:
>> On Thursday, 13 March 2014 at 03:31:09 UTC, ed wrote:
>>> On Thursday, 13 March 2014 at 00:15:19 UTC, Chris Williams wrote:
>>> [snip]
>>>> It shouldn't and probably isn't working.
>>>
>>> It is working and in fact it is in a "const pure @safe" function. So I will trust it  :-)
>>
>> Well it's like a broken watch being correct twice a day. The correct result doesn't mean that something is working.
>
> But this is perfectly valid and safe D code, is it not?
>
> long[4] a=[1,2,3,4];
> int[2][2] b = a.to!(int[]);
>
> which is no different to this:
>
> int[] a_int = a.to!(int[]);
> int[2][2] b = a_int;
>
> Am I missing something here?
>
> Thanks,
> ed

Looking at the disassembly I'm convinced the code is benign and valid D. It just goes through the D runtime which does the full array bounds checking.

As to whether or not this should work:

int[4] a=[1,2,3,4];
int[2][2] b;
b=a;

is up to the D language gurus. I think it should... but I'm no language developer, there may be other side-effects I haven't thought about.

Cheers,
ed

March 14, 2014
On Friday, 14 March 2014 at 04:36:27 UTC, ed wrote:
> As to whether or not this should work:
>
> int[4] a=[1,2,3,4];
> int[2][2] b;
> b=a;
>
> is up to the D language gurus. I think it should... but I'm no language developer, there may be other side-effects I haven't thought about.
>
> Cheers,
> ed

In C, any array is just a starting address in memory. Accessing indexes is accomplished during compile time, where the compiler does some math based on the size of the objects in the array and how many dimensions the array has, then more-or-less hardcodes an offset to add to the starting address. All arrays are mutually exchangeable because they're just a pointer.

In D, an array is a struct (struct Array), with an address and a length value. A multi-dimensional array is an Array with an address pointing to an array of Arrays. So with an int[2][2] array, you have a layout like:

@1000 Array(address=1016, length=2)
@1016 [Array(address=1048, length=2),Array(address=1056, length=2)]
@1048 [1,2]
@1056 [3,4]

In this particular case, the data at 1056 is directly following the data at 1048. There's no gap between them, so considering the buffer at 1048 to be a single array of 4 or two arrays of two is inconsequential. But that's no guarantee. Those two arrays could be off in entirely separate chunks of RAM. In that case, setting a=b would force a copy to occur, since a requires the items to be continguous, where b=a results in both variables pointing to the same underlying data (changing one changes the other).

Now that's assuming that the compiler is actually trying to convert one into the other.

There's the other option of considering a and b to both be of type Array. As such, you can simply copy the values in one over to the other.

a=b; // equivalent to a.address=b.address; a.length=b.length;
b=a; // equivalent to b.address=a.address; b.length=a.length;

This makes complete sense, other than it trashes the settee's type. What was int[2][2] effectively becomes int[4] (or vise-versa), which should then make an access to b[0][1] fail, since the value at entry [0] isn't an Array struct.

Personally, I don't like the inconsistency of the former strategy. People should be forced to implement their own strategy for converting array types (whether to create a copy or point to the same underlying data). For the latter strategy, changing an lvalue's type by setting into it seems like it should only be allowed if you cast. Though since it's the lvalue changing, it would be the lvalue that you would have to cast, and usually a cast only lasts for that line not the rest of time, which wouldn't be the case here so....

cast(int[4])b = a; // ???

Overall, I don't think the compiler should allow the original code. Even if the specification specifies what should happen, the minutiae of it seems prone to creating bugs.
March 14, 2014
On Friday, 14 March 2014 at 19:24:21 UTC, Chris Williams wrote:

[snip]
> address pointing to an array of Arrays. So with an int[2][2] array, you have a layout like:
>
> @1000 Array(address=1016, length=2)
> @1016 [Array(address=1048, length=2),Array(address=1056, length=2)]
> @1048 [1,2]
> @1056 [3,4]
>
> In this particular case, the data at 1056 is directly following the data at 1048. There's no gap between them, so considering the buffer at 1048 to be a single array of 4 or two arrays of two is inconsequential. But that's no guarantee.

Actually this is guaranteed for static rectangular arrays:

http://dlang.org/arrays#static-arrays (see Rectangular Arrays)
http://wiki.dlang.org/Dense_multidimensional_arrays (Static Arrays)

This code below is safe. It is nothing more than a check for conformity followed by a memcpy:

int[] a = [1,2,3,4];
int[2][2] b = a;


I might raise a new question asking why this doesn't work as I expect:

int[2][2] b;
b=a;


Thanks for your help on this one. It has forced me to drill into the internals a bit more, which is always a good thing :)

Cheers,
ed
March 14, 2014
On Friday, 14 March 2014 at 19:24:21 UTC, Chris Williams wrote:

It looks like you might be right after all about the code being invalid D. It could be a bug when it compiles without the cast.

I filed a bug report about it, see where it leads :D

Thanks,
ed
March 22, 2014
On Friday, 14 March 2014 at 19:24:21 UTC, Chris Williams wrote:
> In D, an array is a struct (struct Array), with an address and a length value. A multi-dimensional array is an Array with an address pointing to an array of Arrays. So with an int[2][2] array, you have a layout like:
>
> @1000 Array(address=1016, length=2)
> @1016 [Array(address=1048, length=2),Array(address=1056, length=2)]
> @1048 [1,2]
> @1056 [3,4]

This is not true; you need to distinguish between fixed-size and dynamically sized arrays. It's better to call the latter "slices" to avoid the confusion.

Fixed-size arrays are value types, there are no references/addresses involved in storing them. So this:

int[2][2] a;

always has the following layout:

@1000 [1,2]
@1008 [3,4]

You layout would be correct for this example:

int[][] = [[1,2],[3,4]];
1 2
Next ›   Last »