Thread overview
Casting int[] to ubyte[]: element wise cast or slice cast
Feb 15, 2019
Dennis
Feb 15, 2019
H. S. Teoh
Feb 15, 2019
Dennis
Feb 17, 2019
kdevel
February 15, 2019
I assumed that casting an int[] to a ubyte[] would keep all bytes and quadruple the length of the original array. But when the array is a literal, it keeps the same length but truncates every int element to a ubyte:

```
import std.stdio;

void main()
{
    // enum:
    enum litA = [0x10203040, 0x50607080];
    pragma(msg, typeof(litA));
    ubyte[] a = cast(ubyte[]) litA;

    // auto:
    auto litB = [0x10203040, 0x50607080];
    pragma(msg, typeof(litB));
    ubyte[] b = cast(ubyte[]) litB;

    writeln(a);
    writeln(b);
}
```

Prints:
```
int[]
int[]
[64, 128]
[64, 48, 32, 16, 128, 112, 96, 80]
```

I looked at the spec and found this:

https://dlang.org/spec/expression.html#cast_expressions
"Casting a dynamic array to another dynamic array is done only if the array lengths multiplied by the element sizes match. The cast is done as a type paint, with the array length adjusted to match any change in element size. If there's not a match, a runtime error is generated."

So is this a bug or am I missing something?
February 15, 2019
On Fri, Feb 15, 2019 at 04:17:12PM +0000, Dennis via Digitalmars-d-learn wrote:
> I assumed that casting an int[] to a ubyte[] would keep all bytes and quadruple the length of the original array. But when the array is a literal, it keeps the same length but truncates every int element to a ubyte:

That's correct.  If you want to *transcribe* a ubyte[] to an int[], what you want is probably something like this:

	import std.conv : to;
	ubyte[] data = ...;
	int[] result = data.map!(b => b.to!int).array;


[...]
> I looked at the spec and found this:
> 
> https://dlang.org/spec/expression.html#cast_expressions
> "Casting a dynamic array to another dynamic array is done only if the
> array lengths multiplied by the element sizes match. The cast is done
> as a type paint, with the array length adjusted to match any change in
> element size.  If there's not a match, a runtime error is generated."
> 
> So is this a bug or am I missing something?

Read it again carefully: the casting is done "only if the array lengths multiplied by the element sizes match". In other words:

	T.sizeof * T[].length == U.sizeof * U[].length

Why? because that's the only case where you can reinterpret the .sizeof*.length bytes as an array of a different type.  There is no conversion, the cast works as a reinterpretation.  It's by design.


T

-- 
I'm still trying to find a pun for "punishment"...
February 15, 2019
On Friday, 15 February 2019 at 17:18:28 UTC, H. S. Teoh wrote:
> Why? because that's the only case where you can reinterpret the .sizeof*.length bytes as an array of a different type.  There is no conversion, the cast works as a reinterpretation.  It's by design.

But my problem is that it *isn't* reinterpreted in the case of an enum / array literal, the cast actually transcribes similar to your .map example. Look carefully at the difference of case A and B in my example code: the only difference is whether the int array uses auto or enum.

I'm not going from ubyte to int, I'm going from int to ubyte which should always be possible by multiplying the length by 4, in my case:

int.sizeof * 2 == ubyte.sizeof * 8 == 8

This happens in case B of my example code, but not in case A. There the cast goes from 4*2 bytes to 1*2 instead of 1*8 and I don't get a runtime error.
February 17, 2019
On Friday, 15 February 2019 at 18:11:11 UTC, Dennis wrote:

Your should report our observation: https://issues.dlang.org

```
void main ()
{
   enum A = [0x10203040, 0x50607080]; // shall enum behave like immutable?
   auto B = [0x10203040, 0x50607080];
   assert (A == B);
   auto p = cast (ubyte []) A;
   auto q = cast (ubyte []) B;
   assert (p == q);
}
```