December 15, 2005
Regan Heath wrote:
> On Thu, 15 Dec 2005 00:31:18 -0600, James Dunne <james.jdunne@gmail.com>  wrote:
> 
>> Regan Heath wrote:
>>
>>> On Thu, 15 Dec 2005 02:33:02 +0000 (UTC), Tom  <Tom_member@pathlink.com>  wrote:
>>>
>>>> In article <ops1sym6qr23k2f5@nrage.netwin.co.nz>, Regan Heath says...
>>>
>>>  Both blocks of memory are 4 bytes long. So, apart from one  technically  supposedly being an "int" and the other technically being  "4 bytes in a  row" they're the same thing.
>>>
>>
>> No, it's a bad idea for the D language spec to assume any  implementation-specific details.  In this case, the implementation of a  dynamic array.
> 
> 
> ub is not a dynamic array it is a static array. That said (I believe) you  point is still valid because I can't recall reading anything defining the  static array implementation either (what I know of it is based on  observation and guess work)
> 

Oops on the dynamic array stuff.

>> At no point in the D language spec regarding dynamic arrays is any  ordering of the fields in the implicit memory structure of a dynamic  array stated.  In fact, Walter points out that relying on such  implementation-specific details to get printf working is a bad idea: "In  the future, it may be necessary to just add a new format specifier to  printf() instead of relying on an implementation dependent detail."  (from http://digitalmars.com/d/arrays.html under 'printf() and Strings'  section).
>>
>> What he is referring to is that strings are special-case dynamic arrays.    The printf '%.*s' format specifier expects a length integer followed  by a data pointer.  It just so happens to be (most likely by design)  that the reference DMD compiler orders the dynamic array's fields in  memory as length first, followed by data pointer.
>>
>> Thus, your argument shouldn't hold in general because you're assuming  the D language defines the ordering of the dynamic array's members.
> 
> 
> You make a valid point, for dynamic arrays.. but we're not talking about  dynamic arrays :)
> 

Oops again. :)

>>> However, I do not think it's possible to make a static array point to   another address, so this may be why it fails.
>>>
>>
>> No, the compiler states quite clearly that the cast from an int* to a  ubyte[4] is simply not allowed.  I'm not disagreeing that you cannot  modify the address a static array points to, I'm just disagreeing with  your proposed reason for the 'failure' case.
> 
> 
> There must be some reason the compiler is disallowing it, it's not doing  so just out of spite, right?
> As to what that reason is.. my best guess remains that a static array  pointer is immutable. (which happens to be the implementation that was  chosen by DMD, and is undefined in the spec to my knowledge)
> 

No, the original code posted is not modifying the static array's effective pointer, but is instead attempting to copy the data out of a casted-to ubyte[4] static array.  The cast is what is the invalid operation here.

>> I believe for a cast from a pointer to an array to succeed, both element  types must be exactly equivalent, not just source pointer-element type  castable to destination array-element type.
> 
> 
> AFAIK you can't actually cast from a pointer to an array. Unless you count  what Derek posted:
> 
>   *(cast(int**)(cast(void*)&ub + int.sizeof)) = &i;
> 
> You can however slice a pointer which creates a dynamic array, that's what  happens here:
> 
>   (cast(ubyte*)&i)[0..4];
> 
>>> My code works because you can slice a pointer/memory address to create  a  dynamic array of the type of the pointer. The statement:
>>>    (cast(ubyte*)&i)[0..4];
>>>  creates a temporary dynamic array, which is then copied into the  memory  block pointed to by ub, the static array.
>>>
>>
>> I don't believe this creates any memory. Slices are references to the  original data.  What effectively is being done here is copying 4 ubytes  from the address of a local int variable into the ub[] static array.
> 
> 
> Correct, except when you slice a pointer you get a dynamic array, a  dynamic array consists of a pointer and a length, or 8 bytes of data, so,  unless the compiler optimises this away this statement:
> 
>   ub[] = (cast(ubyte*)&i)[0..4];
> 
> uses 8 bytes of temporary memory on the stack (or is it on the heap?)
> 
> Regan

I believe the implementation of the slice call is defined in the phobos standard library as a regular C function call, so it is not up to the language to decide what to do here.  The memory should be allocated dynamically on the heap, but it is definitely not required to be.  This is another implementation detail.
December 15, 2005
On Thu, 15 Dec 2005 13:56:13 -0600, James Dunne <james.jdunne@gmail.com> wrote:
>>>> However, I do not think it's possible to make a static array point to   another address, so this may be why it fails.
>>>>
>>>
>>> No, the compiler states quite clearly that the cast from an int* to a  ubyte[4] is simply not allowed.  I'm not disagreeing that you cannot  modify the address a static array points to, I'm just disagreeing with  your proposed reason for the 'failure' case.
>>   There must be some reason the compiler is disallowing it, it's not doing  so just out of spite, right?
>> As to what that reason is.. my best guess remains that a static array  pointer is immutable. (which happens to be the implementation that was  chosen by DMD, and is undefined in the spec to my knowledge)
>
> No, the original code posted is not modifying the static array's effective pointer, but is instead attempting to copy the data out of a casted-to ubyte[4] static array.  The cast is what is the invalid operation here.

You're missing my point. Answer me this; the cast is illegal because _______?

You're correct, the original code was not modifying the pointer, my mistake.

But, there must be some reason the cast is illegal. That reason appears to me to be that there is simply no such thing as a temporary static array, perhaps due to the nature/specification of them, perhaps due to the implementation of them, perhaps some other reason...

>>> I believe for a cast from a pointer to an array to succeed, both element  types must be exactly equivalent, not just source pointer-element type  castable to destination array-element type.
>>   AFAIK you can't actually cast from a pointer to an array. Unless you count  what Derek posted:
>>    *(cast(int**)(cast(void*)&ub + int.sizeof)) = &i;
>>  You can however slice a pointer which creates a dynamic array, that's what  happens here:
>>    (cast(ubyte*)&i)[0..4];
>>
>>>> My code works because you can slice a pointer/memory address to create  a  dynamic array of the type of the pointer. The statement:
>>>>    (cast(ubyte*)&i)[0..4];
>>>>  creates a temporary dynamic array, which is then copied into the  memory  block pointed to by ub, the static array.
>>>>
>>>
>>> I don't believe this creates any memory. Slices are references to the  original data.  What effectively is being done here is copying 4 ubytes  from the address of a local int variable into the ub[] static array.
>>   Correct, except when you slice a pointer you get a dynamic array, a  dynamic array consists of a pointer and a length, or 8 bytes of data, so,  unless the compiler optimises this away this statement:
>>    ub[] = (cast(ubyte*)&i)[0..4];
>>  uses 8 bytes of temporary memory on the stack (or is it on the heap?)
>>  Regan
>
> I believe the implementation of the slice call is defined in the phobos standard library as a regular C function call, so it is not up to the language to decide what to do here.  The memory should be allocated dynamically on the heap, but it is definitely not required to be.  This is another implementation detail.

Sure, it's entirely possible a clever implementation can optimise the temporary away. Regardless it's important to understand what is going on figuratively if not actually, as the first usually leads to the other.

Regan
December 15, 2005
On Thu, 15 Dec 2005 18:13:54 +1100, Derek Parnell <derek@psych.ward> wrote:
> On Thu, 15 Dec 2005 02:33:02 +0000 (UTC), Tom wrote:
>
>>> #   ub[] = (cast(ubyte*)&i)[0..4];
>
> Oh... you just wanted to copy the integer to the ub array. Okay.

The alternative to copying is to use a dynamic array instead of a static one, i.e.
  ubyte[] ub;

and to assign rather than copy the result, i.e.
  ub  = (cast(ubyte*)&i)[0..4]

Regan
December 15, 2005
On Thu, 15 Dec 2005 13:56:13 -0600, James Dunne wrote:

BTW, the D Language docs in the ABI section clearly defines the dynamic array implementation structure.

--------------
Arrays
A dynamic array consists of:

offset 	contents
0 	array dimension
4 	pointer to array data

-------------------

So this code is 'legal' but still hackish.

>>   *(cast(int**)(cast(void*)&ub + int.sizeof)) = &i;

-- 
Derek Parnell
Melbourne, Australia
16/12/2005 7:51:40 AM
December 16, 2005
Again people :D, I appreciate the workarounds very much but as I said before, this isn't real code excerpt but a pure abstract example. The only question I'm asking here (and I wish someone can answer) is why is the cast wrong?, as Regan (I think) understood from the very beginning.

Thanks :) Tom

In article <ikigr00oc3am.1aykemsuvx5on.dlg@40tude.net>, Derek Parnell says...
>
>On Thu, 15 Dec 2005 13:56:13 -0600, James Dunne wrote:
>
>BTW, the D Language docs in the ABI section clearly defines the dynamic array implementation structure.
>
>--------------
>Arrays
>A dynamic array consists of:
>
>offset 	contents
>0 	array dimension
>4 	pointer to array data
>
>-------------------
>
>So this code is 'legal' but still hackish.
>
>>>   *(cast(int**)(cast(void*)&ub + int.sizeof)) = &i;
>
>-- 
>Derek Parnell
>Melbourne, Australia
>16/12/2005 7:51:40 AM


December 16, 2005
On Thu, 15 Dec 2005 01:58:59 +0000 (UTC), Tom wrote:

> I'm not sure if someone post this before (maybe this is just a copy-paste, I don't recall as I have the d file missed in some directory and I've just found it), but I'm wondering isn't this cast possible?
> 
> # int main( char[][] args )
> # {
> #   int i;
> #   ubyte[4] ub;
> #   ub[] = cast(ubyte[4]) &i;
> #   return 0;
> # }
> 
> test.d(5): cannot cast int* to ubyte[4]

Oops, I got side tracked ;-)

Ok so here's an attempt at explaining the problem...

The 'cast(ubyte[4])' is telling the compiler to treat the expression that follows as if it was a fixed-size array of 4 ubytes. What follows is '&i' which is the address of an int. So you are asking for the address of an int to be viewed as if it was a block of RAM which is 4 bytes long containing ubytes. But the evaluated expression '&i' is not stored in RAM so the compiler can't paint it with 'ubyte[4]'.

-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
"A learning experience is one of those things that says,
 'You know that thing you just did? Don't do that.'" - D.N. Adams
16/12/2005 2:19:42 PM
December 16, 2005
On Fri, 16 Dec 2005 14:25:34 +1100, Derek Parnell <derek@psych.ward> wrote:
> On Thu, 15 Dec 2005 01:58:59 +0000 (UTC), Tom wrote:
>
>> I'm not sure if someone post this before (maybe this is just a copy-paste, I
>> don't recall as I have the d file missed in some directory and I've just found
>> it), but I'm wondering isn't this cast possible?
>>
>> # int main( char[][] args )
>> # {
>> #   int i;
>> #   ubyte[4] ub;
>> #   ub[] = cast(ubyte[4]) &i;
>> #   return 0;
>> # }
>>
>> test.d(5): cannot cast int* to ubyte[4]
>
> Oops, I got side tracked ;-)
>
> Ok so here's an attempt at explaining the problem...
>
> The 'cast(ubyte[4])' is telling the compiler to treat the expression that
> follows as if it was a fixed-size array of 4 ubytes. What follows is '&i'
> which is the address of an int. So you are asking for the address of an int
> to be viewed as if it was a block of RAM which is 4 bytes long containing
> ubytes. But the evaluated expression '&i' is not stored in RAM so the
> compiler can't paint it with 'ubyte[4]'.

I don't think "not stored in RAM" is the reason, consider:

void main() {
  uint i;
  ubyte[4] ub;
  uint* p = &i;
  ub[] = cast(ubyte[4])p; //e2ir: cannot cast from uint* to ubyte[4]
}

Regan
December 16, 2005
On Fri, 16 Dec 2005 16:37:34 +1300, Regan Heath wrote:

> On Fri, 16 Dec 2005 14:25:34 +1100, Derek Parnell <derek@psych.ward> wrote:
>> On Thu, 15 Dec 2005 01:58:59 +0000 (UTC), Tom wrote:
>>
>>> I'm not sure if someone post this before (maybe this is just a
>>> copy-paste, I
>>> don't recall as I have the d file missed in some directory and I've
>>> just found
>>> it), but I'm wondering isn't this cast possible?
>>>
>>> # int main( char[][] args )
>>> # {
>>> #   int i;
>>> #   ubyte[4] ub;
>>> #   ub[] = cast(ubyte[4]) &i;
>>> #   return 0;
>>> # }
>>>
>>> test.d(5): cannot cast int* to ubyte[4]
>>
>> Oops, I got side tracked ;-)
>>
>> Ok so here's an attempt at explaining the problem...
>>
>> The 'cast(ubyte[4])' is telling the compiler to treat the expression that
>> follows as if it was a fixed-size array of 4 ubytes. What follows is '&i'
>> which is the address of an int. So you are asking for the address of an
>> int
>> to be viewed as if it was a block of RAM which is 4 bytes long containing
>> ubytes. But the evaluated expression '&i' is not stored in RAM so the
>> compiler can't paint it with 'ubyte[4]'.
> 
> I don't think "not stored in RAM" is the reason, consider:
> 
> void main() {
>    uint i;
>    ubyte[4] ub;
>    uint* p = &i;
>    ub[] = cast(ubyte[4])p; //e2ir: cannot cast from uint* to ubyte[4]
> }
> 
> Regan

True ... I think D has made a big mistake in using a single keyword 'cast' to mean 'paint' in some circumstances and 'convert' in others. It is not clear to me when either usage of the keyword is assumed by the compiler.

Also, I can't think of a way to override one meaning of 'cast' to mean the other. So it we really did want to paint 'p' in your example with 'ubyte[4]' how is it done?

-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
"A learning experience is one of those things that says,
 'You know that thing you just did? Don't do that.'" - D.N. Adams
16/12/2005 2:56:37 PM
December 16, 2005
On Fri, 16 Dec 2005 15:12:54 +1100, Derek Parnell <derek@psych.ward> wrote:
> On Fri, 16 Dec 2005 16:37:34 +1300, Regan Heath wrote:
>
>> On Fri, 16 Dec 2005 14:25:34 +1100, Derek Parnell <derek@psych.ward> wrote:
>>> On Thu, 15 Dec 2005 01:58:59 +0000 (UTC), Tom wrote:
>>>
>>>> I'm not sure if someone post this before (maybe this is just a
>>>> copy-paste, I
>>>> don't recall as I have the d file missed in some directory and I've
>>>> just found
>>>> it), but I'm wondering isn't this cast possible?
>>>>
>>>> # int main( char[][] args )
>>>> # {
>>>> #   int i;
>>>> #   ubyte[4] ub;
>>>> #   ub[] = cast(ubyte[4]) &i;
>>>> #   return 0;
>>>> # }
>>>>
>>>> test.d(5): cannot cast int* to ubyte[4]
>>>
>>> Oops, I got side tracked ;-)
>>>
>>> Ok so here's an attempt at explaining the problem...
>>>
>>> The 'cast(ubyte[4])' is telling the compiler to treat the expression that
>>> follows as if it was a fixed-size array of 4 ubytes. What follows is '&i'
>>> which is the address of an int. So you are asking for the address of an
>>> int
>>> to be viewed as if it was a block of RAM which is 4 bytes long containing
>>> ubytes. But the evaluated expression '&i' is not stored in RAM so the
>>> compiler can't paint it with 'ubyte[4]'.
>>
>> I don't think "not stored in RAM" is the reason, consider:
>>
>> void main() {
>>    uint i;
>>    ubyte[4] ub;
>>    uint* p = &i;
>>    ub[] = cast(ubyte[4])p; //e2ir: cannot cast from uint* to ubyte[4]
>> }
>>
>> Regan
>
> True ... I think D has made a big mistake in using a single keyword 'cast'
> to mean 'paint' in some circumstances and 'convert' in others. It is not
> clear to me when either usage of the keyword is assumed by the compiler.
>
> Also, I can't think of a way to override one meaning of 'cast' to mean the
> other. So it we really did want to paint 'p' in your example with
> 'ubyte[4]' how is it done?

I'm not sure you can ever paint something as a static array because you can never assign the result to a static array, because a static array's data pointer is immutable (ignoring the evil hackery you posted) or so it appears to me, eg

void main() {
  uint i;
  ubyte[4] ub;
  uint* p = &i;
  ub = cast(ubyte[4])p; //cannot change reference to static array 'ub'
//cannot assign to static array ub
}

Regan
December 16, 2005
On Fri, 16 Dec 2005 17:42:02 +1300, Regan Heath wrote:

> I'm not sure you can ever paint something as a static array because you can never assign the result to a static array, because a static array's data pointer is immutable (ignoring the evil hackery you posted) or so it appears to me, eg

A fixed-size array (a.k.a static array) does not have a data pointer. It
just sits on the stack as 'x' bytes long.

> void main() {
>    uint i;
>    ubyte[4] ub;

In this case, 'ub' takes up four bytes of stack space. It isn't a pointer to some other four bytes.

>    uint* p = &i;
>    ub = cast(ubyte[4])p; //cannot change reference to static array 'ub'
> //cannot assign to static array ub
> }
> 

But anyways, I would only do this sort of thing using a union.

----------
import std.stdio;
void main() {
    union iu
    {
        uint i;
        ubyte[i.sizeof] ub;
    };
    iu c;

    c.i = 1; // access 'c' as a uint
    writefln("%s", c.ub); // but display 'c' as a ubyte[4]

    c.i = 22;
    writefln("%s", c.ub);
    c.i = 333;
    writefln("%s", c.ub);
    c.i = 4444;
    writefln("%s", c.ub);
}
-----------


-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
"A learning experience is one of those things that says,
 'You know that thing you just did? Don't do that.'" - D.N. Adams
16/12/2005 4:11:16 PM