www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - casting array literals doesn't work as stated in the docs

reply Trass3r <mrmocool gmx.de> writes:
http://www.digitalmars.com/d/2.0/expression.html#ArrayLiteral

The code example from the docs yields [1 1] and [1 0 1 0] instead of [1 
1] and [257] for dmd 2.037.


Additionally

short[] t = [cast(short) 5, 3];
short[] t2 = [cast(short) 5, 3].dup;

void main()
{ ...

yields:

Error: cannot evaluate _adDupT((& D12TypeInfo_G2i6__initZ),[5,3]) at 
compile-time
Error: cannot implicitly convert expression (_adDupT((& 
D12TypeInfo_G2i6__initZ),[5,3])) of type int[] to short[]
Error: cannot evaluate _adDupT((& D12TypeInfo_G2i6__initZ),[5,3]) at 
compile-time


Using int instead of short only removes the second message.


Compiler bug(s)?
Jan 02 2010
parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Sun, 03 Jan 2010 04:23:00 +0300, Trass3r <mrmocool gmx.de> wrote:

 http://www.digitalmars.com/d/2.0/expression.html#ArrayLiteral

 The code example from the docs yields [1 1] and [1 0 1 0] instead of [1  
 1] and [257] for dmd 2.037.


 Additionally

 short[] t = [cast(short) 5, 3];
 short[] t2 = [cast(short) 5, 3].dup;

 void main()
 { ...

 yields:

 Error: cannot evaluate _adDupT((& D12TypeInfo_G2i6__initZ),[5,3]) at  
 compile-time
 Error: cannot implicitly convert expression (_adDupT((&  
 D12TypeInfo_G2i6__initZ),[5,3])) of type int[] to short[]
 Error: cannot evaluate _adDupT((& D12TypeInfo_G2i6__initZ),[5,3]) at  
 compile-time


 Using int instead of short only removes the second message.


 Compiler bug(s)?

Yes and no. It used to work (and should still work), but the behavior was changed to take all array literal values into consideration. "Proper" code should look like this: short[] t = [cast(short) 5, cast(short)3]; which is err... I'll let someone else to decide. Just imagine there are ten (or more) values in an array literal.
Jan 02 2010
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sat, 02 Jan 2010 20:54:30 -0500, Denis Koroskin <2korden gmail.com>  
wrote:

 On Sun, 03 Jan 2010 04:23:00 +0300, Trass3r <mrmocool gmx.de> wrote:

 http://www.digitalmars.com/d/2.0/expression.html#ArrayLiteral

 The code example from the docs yields [1 1] and [1 0 1 0] instead of [1  
 1] and [257] for dmd 2.037.


 Additionally

 short[] t = [cast(short) 5, 3];
 short[] t2 = [cast(short) 5, 3].dup;

 void main()
 { ...

 yields:

 Error: cannot evaluate _adDupT((& D12TypeInfo_G2i6__initZ),[5,3]) at  
 compile-time
 Error: cannot implicitly convert expression (_adDupT((&  
 D12TypeInfo_G2i6__initZ),[5,3])) of type int[] to short[]
 Error: cannot evaluate _adDupT((& D12TypeInfo_G2i6__initZ),[5,3]) at  
 compile-time


 Using int instead of short only removes the second message.


 Compiler bug(s)?

Yes and no. It used to work (and should still work), but the behavior was changed to take all array literal values into consideration. "Proper" code should look like this: short[] t = [cast(short) 5, cast(short)3]; which is err... I'll let someone else to decide. Just imagine there are ten (or more) values in an array literal.

the cast-entire-array takes care of that. Corrected docs example: short[] rt = cast(short[]) (cast(byte[])[1, 1]).dup; Note the cast of the entire literal, not just the first element. so now, if you want to set the type of the array, cast the entire array. If you want to set the type of only one element, cast that one element, but the runtime might decide to use a bigger type anyways. correcting your code: short[] t = cast(short[])[5,3]; short[] t2 = cast(short[])[5,3].dup; -Steve
Jan 02 2010
next sibling parent reply Trass3r <mrmocool gmx.de> writes:
Steven Schveighoffer schrieb:
 short[] t = cast(short[])[5,3];
 short[] t2 = cast(short[])[5,3].dup;
 

Second one still doesn't work at compile-time.
Jan 03 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Trass3r:
 short[] t = cast(short[])[5,3];
 short[] t2 = cast(short[])[5,3].dup;
 

Second one still doesn't work at compile-time.

It's not supposed to work, "dup" allocated memory with malloc, so it's (currently) a run time thing (in future this may change). Bye, bearophile
Jan 03 2010
prev sibling parent reply Trass3r <mrmocool gmx.de> writes:
Steven Schveighoffer schrieb:
 if you cast an array literal, then it reinterprets each element as if 
 each element were cast to that type.
 
 otherwise, it's a reinterpret_cast as you say.
 

Any reason for defining the behavior like that? The problem is forcing the compiler to reinterpret_cast at compile-time. Using .dup like in the docs doesn't work: http://codepad.org/P9EZ0dIB without using the ugly auto PALETTE = (cast(RGBA*) cast(ubyte[]) [0xFF,...]) [0 .. 256];
Jan 03 2010
parent Trass3r <mrmocool gmx.de> writes:
Trass3r schrieb:
  Any reason for defining the behavior like that?
 

I mean converting an array to an array of structs doesn't make sense as soon as you have multiple struct members cause cast(Foo[])[0,1,2,3,4] gets rewritten as [cast(Foo) 0, cast(Foo) 1, cast(Foo) 2, cast(Foo) 3, cast(Foo) 4] which becomes [Foo(0), Foo(1), Foo(2), Foo(3), Foo(4)] if I didn't miss anything.
Jan 03 2010
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Sun, 03 Jan 2010 05:56:21 +0300, Steven Schveighoffer  
<schveiguy yahoo.com> wrote:

 On Sat, 02 Jan 2010 20:54:30 -0500, Denis Koroskin <2korden gmail.com>  
 wrote:

 On Sun, 03 Jan 2010 04:23:00 +0300, Trass3r <mrmocool gmx.de> wrote:

 http://www.digitalmars.com/d/2.0/expression.html#ArrayLiteral

 The code example from the docs yields [1 1] and [1 0 1 0] instead of  
 [1 1] and [257] for dmd 2.037.


 Additionally

 short[] t = [cast(short) 5, 3];
 short[] t2 = [cast(short) 5, 3].dup;

 void main()
 { ...

 yields:

 Error: cannot evaluate _adDupT((& D12TypeInfo_G2i6__initZ),[5,3]) at  
 compile-time
 Error: cannot implicitly convert expression (_adDupT((&  
 D12TypeInfo_G2i6__initZ),[5,3])) of type int[] to short[]
 Error: cannot evaluate _adDupT((& D12TypeInfo_G2i6__initZ),[5,3]) at  
 compile-time


 Using int instead of short only removes the second message.


 Compiler bug(s)?

Yes and no. It used to work (and should still work), but the behavior was changed to take all array literal values into consideration. "Proper" code should look like this: short[] t = [cast(short) 5, cast(short)3]; which is err... I'll let someone else to decide. Just imagine there are ten (or more) values in an array literal.

the cast-entire-array takes care of that. Corrected docs example: short[] rt = cast(short[]) (cast(byte[])[1, 1]).dup; Note the cast of the entire literal, not just the first element. so now, if you want to set the type of the array, cast the entire array. If you want to set the type of only one element, cast that one element, but the runtime might decide to use a bigger type anyways. correcting your code: short[] t = cast(short[])[5,3]; short[] t2 = cast(short[])[5,3].dup; -Steve

Array casting is something I avoid as a plague. It is highly inconsistent: in some cases, it does bitwise casting (kind of a reinterpret_cast, changing size of an array), in others - in creates per-element copy of an array, thus doing at runtime something I'd like to be done at compile-time. Maybe it's just me, but I wouldn't recommend anyone using array casting (other that T[] -> void[]).
Jan 02 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sat, 02 Jan 2010 22:41:05 -0500, Denis Koroskin <2korden gmail.com>  
wrote:


 Array casting is something I avoid as a plague. It is highly  
 inconsistent: in some cases, it does bitwise casting (kind of a  
 reinterpret_cast, changing size of an array), in others - in creates  
 per-element copy of an array, thus doing at runtime something I'd like  
 to be done at compile-time.

 Maybe it's just me, but I wouldn't recommend anyone using array casting  
 (other that T[] -> void[]).

It's very consistent. It never does a per-element copy at runtime. Essentially, doing this: cast(byte[])[a, b, c] is equivalent to doing this: [cast(byte)a, cast(byte)b, cast(byte)c] the rules are: if you cast an array literal, then it reinterprets each element as if each element were cast to that type. otherwise, it's a reinterpret_cast as you say. -Steve
Jan 02 2010
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Denis Koroskin:
 "Proper" code should look like this:
 short[] t = [cast(short) 5, cast(short)3];
 which is err... I'll let someone else to decide. Just imagine there are  
 ten (or more) values in an array literal.

What's wrong with just (D2 code): short[] a3 = [5, 3]; Bye, bearophile
Jan 03 2010
parent reply Trass3r <mrmocool gmx.de> writes:
bearophile schrieb:
 What's wrong with just (D2 code):
 short[] a3 = [5, 3];
 

Nothing, but it's just the stripped down example. auto t = [0xFF, 0x00]; yields int[] so for struct Foo { ...} auto x = cast(Foo[]) [0x00, 0x01,...]; you need an additional cast(ubyte[]). Yet this doesn't work: http://codepad.org/P9EZ0dIB
Jan 03 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Trass3r:

 What's wrong with just (D2 code):
 short[] a3 = [5, 3];


I was not answering you, but what Denis Koroskin has written. This thread is getting too much confused. And I think I have already seen a very similar thread elsewhere.
 auto t = [0xFF, 0x00];
 yields int[]

That's the correct thing. Ints are the default because D2 doesn't defaults to optimized multi-precision integral values as CLisp.
 Yet this doesn't work:
 http://codepad.org/P9EZ0dIB

module main; import std.stdio, std.string; struct RGBA { ubyte r; ubyte g; ubyte b; ubyte a; string toString() { return format("{%s, %s, %s, %s}", r, g, b, a); } } static f = cast(RGBA[]) cast(ubyte[])[0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70]; static g = cast(RGBA[]) cast(ubyte[])[0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70].dup; enum h = cast(ubyte[])[0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70].dup; static h2 = cast(RGBA[]) h.dup; enum h3 = cast(RGBA[]) h; void main() { writeln(f); writeln(h2); writeln(h3); } I don't like that code. So, do you want to define an array of 4-bytes structs? What's wrong with: // qualified imports import std.stdio: writeln; import std.string: format; struct RGBA { ubyte r, g, b, a; string toString() { return format("{%s, %s, %s, %s}", r, g, b, a); } } // alternative 1: enum RGBA[] data1 = [{0x00, 0x10, 0x20, 0x30}, {0x40, 0x50, 0x60, 0x70}]; // alternative 2: enum RGBA[] data2 = [RGBA(0x00, 0x10, 0x20, 0x30), RGBA(0x40, 0x50, 0x60, 0x70)]; void main() { writeln(data1); writeln(data2); } Bye, bearophile
Jan 03 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Trass3r:
 Alternative 1: I heard struct literals could be removed.

I haven't heard that. They are recently changed a little, but you already know that from another thread.
 Alternative 2:
 1) it's cumbersome, especially if you got a huge array

But it's clean & readable, and more flexible because later you can add a static opCall that does what you want. You can use a Python script or an IDE to generate the D code.
 I currently use the old casting hack:
 auto PALETTE = (cast(RGBA*) cast(ubyte[]) [0xFF,...]) [0 .. 256];

This looks OK for a 20 lines long script for your personal usage, but I refuse it in production code. The code must be first of all tidy, and it must use a clean semantics, unless you have already profiled the code and found out that a spot is not fast enough for the program users. Unless otherwise required, you must program as your stereotypical granny drives, or later the code will bite your rear :-) Bye, bearophile
Jan 03 2010
prev sibling next sibling parent Trass3r <un known.com> writes:
Am 03.01.2010, 12:20 Uhr, schrieb bearophile <bearophileHUGS lycos.com>:
 It's not supposed to work, "dup" allocated memory with malloc, so it's  
 (currently) a run time thing (in future this may change).

So how to "create" an array expression at compile-time to enforce reinterpret_cast instead of conversion? // cast array literal const short[] ct = cast(short[]) [cast(byte)1, 1]; writeln(ct); // writes [1 1] // cast other array expression short[] rt = cast(short[]) [cast(byte)1, 1].dup; writeln(rt); // writes [257]
Jan 03 2010
prev sibling next sibling parent Trass3r <un known.com> writes:
Am 03.01.2010, 12:33 Uhr, schrieb bearophile <bearophileHUGS lycos.com>:

 // alternative 1:
 enum RGBA[] data1 = [{0x00, 0x10, 0x20, 0x30}, {0x40, 0x50, 0x60, 0x70}];
 // alternative 2:
 enum RGBA[] data2 = [RGBA(0x00, 0x10, 0x20, 0x30), RGBA(0x40, 0x50,  
 0x60, 0x70)];

Alternative 1: I heard struct literals could be removed. Alternative 2: 1) it's cumbersome, especially if you got a huge array 2) if you somehow fundamentally change the struct for whatever reason, you probably have to reassign everything. I currently use the old casting hack: auto PALETTE = (cast(RGBA*) cast(ubyte[]) [0xFF,...]) [0 .. 256]; I just ask if it's possible to do it in a nicer way, i.e. either 1) the current behavior needs to be changed so casting to arrays of structs always does a reinterpret_cast or 2) there must be some way to turn an array literal into an array expression at compile-time (i.e. without using .dup) to force reinterpretation.
Jan 03 2010
prev sibling next sibling parent Trass3r <un known.com> writes:
Am 03.01.2010, 14:00 Uhr, schrieb bearophile <bearophileHUGS lycos.com>:

 Trass3r:
 Alternative 1: I heard struct literals could be removed.

I haven't heard that. They are recently changed a little, but you already know that from another thread.

I read somewhere it might conflict with function literals: {...}
 Alternative 2:
 1) it's cumbersome, especially if you got a huge array

But it's clean & readable, and more flexible because later you can add a static opCall that does what you want. You can use a Python script or an IDE to generate the D code.

I don't need to be flexible. In this simple case I only need a reinterpret_cast. A good language like D should provide a neat, clean way to accomplish that without involving another language or tool (which in fact is already supported but it simply doesn't work at compile-time that way)
Jan 03 2010
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 03 Jan 2010 06:53:53 -0500, Trass3r <un known.com> wrote:

 Am 03.01.2010, 12:33 Uhr, schrieb bearophile <bearophileHUGS lycos.com>:

 // alternative 1:
 enum RGBA[] data1 = [{0x00, 0x10, 0x20, 0x30}, {0x40, 0x50, 0x60,  
 0x70}];
 // alternative 2:
 enum RGBA[] data2 = [RGBA(0x00, 0x10, 0x20, 0x30), RGBA(0x40, 0x50,  
 0x60, 0x70)];

Alternative 1: I heard struct literals could be removed. Alternative 2: 1) it's cumbersome, especially if you got a huge array 2) if you somehow fundamentally change the struct for whatever reason, you probably have to reassign everything. I currently use the old casting hack: auto PALETTE = (cast(RGBA*) cast(ubyte[]) [0xFF,...]) [0 .. 256];

You should be able to do this I would think: auto PALETTE = cast(RGBA[])(cast(ubyte[])[0xFF,..])); but it doesn't work. I think it probably should. Why would I cast each element to byte only to then cast to RGBA. I think the parentheses should make it clear how I want the cast to proceed. I agree there should be a way to invoke the "bitwise" cast in one line besides the hackish way you are forced to do it. -Steve
Jan 03 2010