to! converting 1D to 2D array

Chris Williams yoreanon-chrisw at yahoo.co.jp
Fri Mar 14 12:24:20 PDT 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.


More information about the Digitalmars-d-learn mailing list