www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - inout/out static array parameter

reply Tom <Tom_member pathlink.com> writes:
Why is this illegal? Where does the documentation states this?
Does it have something to do with the matter that int[10] is allocated onto the
stack? Sometimes I think D losses its abstraction capability when one has to be
concerned about this kind of differences.






test.d(5): cannot have out or inout parameter of type int[10]

(dmd.147 Win)

Thanks,

Tom;
Feb 21 2006
parent reply Derek Parnell <derek psych.ward> writes:
On Wed, 22 Feb 2006 03:02:22 +0000 (UTC), Tom wrote:

 Why is this illegal? Where does the documentation states this?
 Does it have something to do with the matter that int[10] is allocated onto the
 stack? Sometimes I think D losses its abstraction capability when one has to be
 concerned about this kind of differences.
 




 
 test.d(5): cannot have out or inout parameter of type int[10]
I cannot see why D should be upset with this. The implementation would be just be passing the address of the int[10] array, just as it does for 'in' parameters. In conceptual terms, it is identical to this, which D does allow ... struct X { int[10] x; } void f(inout X q) { q.x[0..$] = 99; } -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocracy!" 22/02/2006 2:07:00 PM
Feb 21 2006
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Wed, 22 Feb 2006 14:15:32 +1100, Derek Parnell <derek psych.ward> wrote:
 On Wed, 22 Feb 2006 03:02:22 +0000 (UTC), Tom wrote:

 Why is this illegal? Where does the documentation states this?
 Does it have something to do with the matter that int[10] is allocated  
 onto the
 stack? Sometimes I think D losses its abstraction capability when one  
 has to be
 concerned about this kind of differences.






 test.d(5): cannot have out or inout parameter of type int[10]
I cannot see why D should be upset with this. The implementation would be just be passing the address of the int[10] array, just as it does for 'in' parameters.
Not quite, when you pass something as 'in' you always get a copy of it, this is true even for arrays. The important thing to realise is exactly what it's passing/copying. In this case: int[10] data; void foo(int[10] a) {} foo(data); You're passing a pointer to the array data, 'in' copies that pointer and passes the copy. In this case: int[10] data; void foo(inout int[10] a) {} foo(data); You're not passing a copy of the pointer to the array data, you're passing the actual pointer. As we all know static/fixed arrays have a fixed data pointer which cannot be assigned to or changed in any way. Therefore it's illegal to pass that pointer as 'inout'.
 In conceptual terms, it is identical to this, which D does
 allow ...

 struct X
 {
     int[10] x;
 }
 void f(inout X q)
 {
 	q.x[0..$] = 99;
 }
I think it depends on what "conceptual" really means in this case, in terms of "how it works"(TM) I think it's closer to this: const int* data; void foo(inout int* p) {} void bar(int* p) {} void main() { bar(data); foo(data); } which gives: "can only initialize const data inside constructor" for the call to "foo". Note: If you modify p in bar, print the value of data before and after the call and initialise it to the address of an int you'll see that 'p' really is a copy of 'data'. Regan
Feb 21 2006
parent reply Derek Parnell <derek psych.ward> writes:
On Wed, 22 Feb 2006 17:16:30 +1300, Regan Heath wrote:

 On Wed, 22 Feb 2006 14:15:32 +1100, Derek Parnell <derek psych.ward> wrote:
 On Wed, 22 Feb 2006 03:02:22 +0000 (UTC), Tom wrote:

 Why is this illegal? Where does the documentation states this?
 Does it have something to do with the matter that int[10] is allocated  
 onto the
 stack? Sometimes I think D losses its abstraction capability when one  
 has to be
 concerned about this kind of differences.






 test.d(5): cannot have out or inout parameter of type int[10]
I cannot see why D should be upset with this. The implementation would be just be passing the address of the int[10] array, just as it does for 'in' parameters.
Not quite, when you pass something as 'in' you always get a copy of it, this is true even for arrays.
I don't believe that to be entirely accurate. For example, if you pass an 'int' as an 'in' parameter you get a 'mov EAX,<var>' generated, but if you pass the same variable as an 'inout' you get a 'lea EAX,<var>' generated. To me this is saying that whenever an 'inout' parameter is passed, it is the actual address of that parameter passed. Even when the variable is a class instance. In that case an 'in' parameter gets the value of the object reference and an 'inout' gets the address of the object reference. The same with variable-length arrays. However when we get to fixed length arrays, the 'in/inout/out' regime is gets fubar'ed. You can pass a fixed-length array with an 'in' parameter and what get's passed is the address of the first item in the array - which means that the function is free to modify the contents (yes it is an 'in' parameter) but of course the address of the data is not changed (that's what 'in' is really protecting). So in effect, for fixed-length arrays, 'in' and 'inout' are synonymous. Which is not what a normal person would guess. So why not allow 'inout' with fixed-length arrays? Isn't this how a coder would tell the reader that he *intends* to change the passed array's data and 'in' is telling the reader that the coder does NOT intend to change the data.
 The important thing to realise is exactly  
 what it's passing/copying.
 
 In this case:
 
 int[10] data;
 void foo(int[10] a) {}
 foo(data);
 
 You're passing a pointer to the array data, 'in' copies that pointer and  
 passes the copy.
It doesn't actually copy the pointer, it just passes the address of the data ("lea EAX,-8[EBP]").
 In this case:
 
 int[10] data;
 void foo(inout int[10] a) {}
 foo(data);
 
 You're not passing a copy of the pointer to the array data, you're passing  
 the actual pointer. 
No, that's what 'in' does.
As we all know static/fixed arrays have a fixed data  
 pointer which cannot be assigned to or changed in any way. Therefore it's  
 illegal to pass that pointer as 'inout'.
Yes, I can see the logic of this, given that 'in' is designed to protect the reference to the data and not the data itself. To have 'inout' in this context would imply that the coder is trying to change the address of the data and that is obviously not allowed. This fundamental principle of D is not explained well enough in the documentation. 'in' protects that data passed to the function such that any change that the function performs on the passed data, is not passed back to the calling code. For fixed-length arrays the data is the address of first element For variable-length arrays the data is the length of the array and address of the the first element For objects the data is the object reference For structs thee data is the address of the struct contents For intrinsic items the data is the value of the variable.
 In conceptual terms, it is identical to this, which D does
 allow ...

 struct X
 {
     int[10] x;
 }
 void f(inout X q)
 {
 	q.x[0..$] = 99;
 }
I think it depends on what "conceptual" really means in this case, in terms of "how it works"(TM) I think it's closer to this:
No, I wasn't thinking "implementation" I was thinking "common sense". -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocracy!" 22/02/2006 3:31:20 PM
Feb 21 2006
next sibling parent "Regan Heath" <regan netwin.co.nz> writes:
On Wed, 22 Feb 2006 16:09:47 +1100, Derek Parnell <derek psych.ward> wrote:
 I think it depends on what "conceptual" really means in this case, in
 terms of "how it works"(TM) I think it's closer to this:
No, I wasn't thinking "implementation" I was thinking "common sense".
Arrays are passed as references (AKA "array reference"). Passing a static/constant reference as 'inout' should be illegal. Is that not common sense? Regan
Feb 21 2006
prev sibling parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Wed, 22 Feb 2006 16:09:47 +1100, Derek Parnell <derek psych.ward> wrote:
 On Wed, 22 Feb 2006 17:16:30 +1300, Regan Heath wrote:

 On Wed, 22 Feb 2006 14:15:32 +1100, Derek Parnell <derek psych.ward>  
 wrote:
 On Wed, 22 Feb 2006 03:02:22 +0000 (UTC), Tom wrote:

 Why is this illegal? Where does the documentation states this?
 Does it have something to do with the matter that int[10] is allocated
 onto the
 stack? Sometimes I think D losses its abstraction capability when one
 has to be
 concerned about this kind of differences.






 test.d(5): cannot have out or inout parameter of type int[10]
I cannot see why D should be upset with this. The implementation would be just be passing the address of the int[10] array, just as it does for 'in' parameters.
Not quite, when you pass something as 'in' you always get a copy of it, this is true even for arrays.
I don't believe that to be entirely accurate. For example, if you pass an 'int' as an 'in' parameter you get a 'mov EAX,<var>' generated, but if you pass the same variable as an 'inout' you get a 'lea EAX,<var>' generated.
My knowledge of assembler is practically non existant. Does the 'mov' copy the var into EAX? Does 'lea' copy the address of the var into EAX? Is EAX the parameter to the function? Due to my lack of assembler I can't really back any of my thoughts up with evidence but I'll try and explain what I think is going on...
 To me this is saying that whenever an 'inout' parameter is passed, it is
 the actual address of that parameter passed. Even when the variable is a
 class instance.
I agree. The key issue is in fact what <var> is in each case. When you pass an int <var> is an int, when you pass a class reference <var> is a class reference, when you pass an array reference <var> is an array reference. So as not to confuse things I'm using the word "variable" to describe 'a' and "parameter" to describe 'b' below. void function(inout int[10] b) {} int[10] a; function(a); What I believe 'inout' does is alias the variable with the parameter. In the case of an array reference <var> is an array reference and the parameter 'b' is therefore simply another name for the same array reference variable 'a'. Modifying the value of 'b' modifies the value of 'a' (and vice-versa. I wonder if I can proove this by using a thread to modify the variable...) The same is true for any inout variable.
 In that case an 'in' parameter gets the value of the object reference
I agree. In all cases an 'in' parameter gets the value of the <var> which is passed. If <var> is an int you get a new int with the same value, if <var> is a class reference you get a new class reference with the same value, if var is an array reference you get a new array reference with the same value. In all cases 'in' results in a parameter with the same value as the variable. eg. void function(int[10] b) {} int[10] a; function(a); So, 'b' is a brand new array reference with the same value as 'a'. 'b' is a copy of 'a'. The value of a fixed-length array reference is the address of the first item in the array. The value of a variable length array reference is different. It is the address of a struct with a length and data pointer. In other words both array references are pointers (to different things) and their behaviour ends up being the same for both 'in' and 'inout'.
 and an 'inout' gets the address of the object reference. The same with  
 variable-length arrays. However when we get to fixed length arrays,
 the 'in/inout/out' regime is gets fubar'ed.
I don't agree, my reasoning follows..
 You can pass a fixed-length
 array with an 'in' parameter and what get's passed is the address of the
 first item in the array
Or rather, a new array reference which has the same value as the original array reference. That value being the memory location of the first item in the array.
 - which means that the function is free to modify
 the contents (yes it is an 'in' parameter) but of course the address of  
 the data is not changed (that's what 'in' is really protecting).
Correct.
 So in effect, for fixed-length arrays, 'in' and 'inout' are synonymous.
I don't agree. 'inout' aliases the original array reference. 'in' gives you a new array reference with the same value. That is the difference.
 Which is not what
 a normal person would guess. So why not allow 'inout' with fixed-length
 arrays? Isn't this how a coder would tell the reader that he *intends* to
 change the passed array's data and 'in' is telling the reader that the
 coder does NOT intend to change the data.
WRT array/class references/pointers 'in' promises only 1 thing, that the function will not modify the original array reference. It can promise this because the function always gets a copy of the reference and not the original reference itself. It makes no promise about the content of the array, just like it makes no promise about the content of a class.
 The important thing to realise is exactly
 what it's passing/copying.

 In this case:

 int[10] data;
 void foo(int[10] a) {}
 foo(data);

 You're passing a pointer to the array data, 'in' copies that pointer and
 passes the copy.
It doesn't actually copy the pointer, it just passes the address of the data ("lea EAX,-8[EBP]").
The "address of the data" is the value of the fixed-length array reference. Copying that value to a new location creates a new array reference, to the same data, a copy of the array reference. In other words, 'in' copies the array reference.
 In this case:

 int[10] data;
 void foo(inout int[10] a) {}
 foo(data);

 You're not passing a copy of the pointer to the array data, you're  
 passing
 the actual pointer.
No, that's what 'in' does.
I think we're disagreeing to the meaning of the terms we're using :) specifically what "passing" means.
 As we all know static/fixed arrays have a fixed data
 pointer which cannot be assigned to or changed in any way. Therefore  
 it's
 illegal to pass that pointer as 'inout'.
Yes, I can see the logic of this, given that 'in' is designed to protect the reference to the data and not the data itself.
Agreed.
 To have 'inout' in this
 context would imply that the coder is trying to change the address of the
 data and that is obviously not allowed.
Agreed.
 This fundamental principle of D is not explained well enough in the
 documentation.

 'in' protects that data passed to the function such that any change that
 the function performs on the passed data, is not passed back to the  
 calling
 code.
    For fixed-length arrays the data is the address of first element
    For variable-length arrays the data is the length of the array
          and address of the the first element
    For objects the data is the object reference
    For structs thee data is the address of the struct contents
    For intrinsic items the data is the value of the variable.
I didn't realise this documentation even existed :) I think it does a good job of explaining how it works. I especially like that it tells us what the 2 types of array reference actually are. Regan
Feb 22 2006
next sibling parent "Regan Heath" <regan netwin.co.nz> writes:
On Wed, 22 Feb 2006 23:05:37 +1300, Regan Heath <regan netwin.co.nz> wrote:
 So as not to confuse things I'm using the word "variable" to describe  
 'a' and "parameter" to describe 'b' below.

 void function(inout int[10] b) {}
 int[10] a;
 function(a);

 What I believe 'inout' does is alias the variable with the parameter. In  
 the case of an array reference <var> is an array reference and the  
 parameter 'b' is therefore simply another name for the same array  
 reference variable 'a'. Modifying the value of 'b' modifies the value of  
 'a' (and vice-versa. I wonder if I can proove this by using a thread to  
 modify the variable...)
No threads required to proove aliasing. void foo(inout int a) { printf("addr(a)=0x%08x\n",&a); } void main() { int i; printf("addr(i)=0x%08x\n",&i); foo(i); } Output: addr(i)=0x0012ff34 addr(a)=0x0012ff34 'i' and 'a' are the same int. 'a' is an alias for 'i'. Regan
Feb 22 2006
prev sibling parent reply Tom <Tom_member pathlink.com> writes:
In article <ops5dcznaa23k2f5 nrage.netwin.co.nz>, Regan Heath says...
On Wed, 22 Feb 2006 16:09:47 +1100, Derek Parnell <derek psych.ward> wrote:
 On Wed, 22 Feb 2006 17:16:30 +1300, Regan Heath wrote:

 On Wed, 22 Feb 2006 14:15:32 +1100, Derek Parnell <derek psych.ward>  
 wrote:
 On Wed, 22 Feb 2006 03:02:22 +0000 (UTC), Tom wrote:

 Why is this illegal? Where does the documentation states this?
 Does it have something to do with the matter that int[10] is allocated
 onto the
 stack? Sometimes I think D losses its abstraction capability when one
 has to be
 concerned about this kind of differences.






 test.d(5): cannot have out or inout parameter of type int[10]
I cannot see why D should be upset with this. The implementation would be just be passing the address of the int[10] array, just as it does for 'in' parameters.
Not quite, when you pass something as 'in' you always get a copy of it, this is true even for arrays.
This isn't true: void f(in int[10] x) { x[0] = 99; } int[10] i; f(i); printf("%d\n", i[0]); // prints '99' So you get a copy of the pointer to the first element. That's plain useless for everyone. I dream 'in' could protect content of the array someday. This is far from abstract a programmer from what's really happening. If I code something like: void f(in int[10] x); Common sense will tell me that the 10 positions of my array are well protected and they shouldn't be touched by 'f' and in return this isn't the behavior. Walter with all respect, this sucks! When will we have real protection attributes? So the 'in' keyword for static arrays are perfectly useless and introduces nothing (while in the background it is really "protecting" the pointer to the first element -that doesn't need any protection-). Regards, Tom;
Feb 22 2006
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Wed, 22 Feb 2006 11:42:15 +0000 (UTC), Tom <Tom_member pathlink.com>  
wrote:
 In article <ops5dcznaa23k2f5 nrage.netwin.co.nz>, Regan Heath says...
 On Wed, 22 Feb 2006 16:09:47 +1100, Derek Parnell <derek psych.ward>  
 wrote:
 On Wed, 22 Feb 2006 17:16:30 +1300, Regan Heath wrote:

 On Wed, 22 Feb 2006 14:15:32 +1100, Derek Parnell <derek psych.ward>
 wrote:
 On Wed, 22 Feb 2006 03:02:22 +0000 (UTC), Tom wrote:

 Why is this illegal? Where does the documentation states this?
 Does it have something to do with the matter that int[10] is  
 allocated
 onto the
 stack? Sometimes I think D losses its abstraction capability when  
 one
 has to be
 concerned about this kind of differences.






 test.d(5): cannot have out or inout parameter of type int[10]
I cannot see why D should be upset with this. The implementation would be just be passing the address of the int[10] array, just as it does for 'in' parameters.
Not quite, when you pass something as 'in' you always get a copy of it, this is true even for arrays.
This isn't true:
Yes, it is. The key is realising what it is you're actually passing, in this case an array reference. You're not passing the data which is in the array, just the reference to it.
 void f(in int[10] x)
 {
 x[0] = 99;
 }

 int[10] i;
 f(i);
 printf("%d\n", i[0]); // prints '99'

 So you get a copy of the pointer to the first element. That's plain  
 useless for
 everyone. I dream 'in' could protect content of the array someday.
See my last reply. The thing you get a copy of is the array reference, not the data to which it refers. The array reference is a pointer which points to the location in memory where the array data is stored, this address is also the location of the first array element, much like: char *p = strdup("this is a test"); the address to which p points is the location of the character 't' from the word 'this'. A fixed-length array is very similar to a plain old pointer, except it also has array bounds checking and a hard coded length available, plus useful array operations. See the docs Derek posted in his last reply, 'in' does not promise to protect the data to which the array reference refers, only the array reference itself.
 This is far from abstract a programmer from what's really happening. If  
 I code
 something like:

 void f(in int[10] x);

 Common sense will tell me that the 10 positions of my array are well  
 protected
 and they shouldn't be touched by 'f' and in return this isn't the  
 behavior.
I think everyone (including Walter) wants us to be able to do this sort of thing. Whether it's a good idea isn't really in doubt, what is, is how it can be implemented.
 Walter with all respect, this sucks! When will we have real protection
 attributes?
I suspect we'll have them as soon as Walter devises a way to implement them to his satisfaction.
 So the 'in' keyword for static arrays are perfectly useless and  
 introduces nothing (while in the background it is really "protecting"  
 the pointer to the first element -that doesn't need any protection-).
The 'in' keyword behaves the same way for arrays, classes and any other reference type, it protects the reference itself, not the data to which the reference refers. Regan
Feb 22 2006
parent reply Tom <Tom_member pathlink.com> writes:
In article <ops5dii4gc23k2f5 nrage.netwin.co.nz>, Regan Heath says...
On Wed, 22 Feb 2006 11:42:15 +0000 (UTC), Tom <Tom_member pathlink.com>  
wrote:
 In article <ops5dcznaa23k2f5 nrage.netwin.co.nz>, Regan Heath says...
 On Wed, 22 Feb 2006 16:09:47 +1100, Derek Parnell <derek psych.ward>  
 wrote:
 On Wed, 22 Feb 2006 17:16:30 +1300, Regan Heath wrote:

 On Wed, 22 Feb 2006 14:15:32 +1100, Derek Parnell <derek psych.ward>
 wrote:
 On Wed, 22 Feb 2006 03:02:22 +0000 (UTC), Tom wrote:

 Why is this illegal? Where does the documentation states this?
 Does it have something to do with the matter that int[10] is  
 allocated
 onto the
 stack? Sometimes I think D losses its abstraction capability when  
 one
 has to be
 concerned about this kind of differences.






 test.d(5): cannot have out or inout parameter of type int[10]
I cannot see why D should be upset with this. The implementation would be just be passing the address of the int[10] array, just as it does for 'in' parameters.
Not quite, when you pass something as 'in' you always get a copy of it, this is true even for arrays.
This isn't true:
Yes, it is. The key is realising what it is you're actually passing, in this case an array reference. You're not passing the data which is in the array, just the reference to it.
I know, I thought you meant that 'in' makes a copy of the whole array, not the pointer to it. There's no copy of the array itself.
 void f(in int[10] x)
 {
 x[0] = 99;
 }

 int[10] i;
 f(i);
 printf("%d\n", i[0]); // prints '99'

 So you get a copy of the pointer to the first element. That's plain  
 useless for
 everyone. I dream 'in' could protect content of the array someday.
See my last reply. The thing you get a copy of is the array reference, not the data to which it refers.
Think my post declares clearly that I KNOW THAT.
The array reference is a pointer which points  
to the location in memory where the array data is stored, this address is  
also the location of the first array element, much like:

char *p = strdup("this is a test");

the address to which p points is the location of the character 't' from  
the word 'this'. A fixed-length array is very similar to a plain old  
pointer, except it also has array bounds checking and a hard coded length  
available, plus useful array operations.
Agree.
See the docs Derek posted in his last reply, 'in' does not promise to  
protect the data to which the array reference refers, only the array  
reference itself.
Sorry, I didn't understand Derek copied that from docs -in fact I can't find that in the docs [please guide me with a link if you do]-, but rather I think that is his own version of what he think the docs should state (or what has to be added to the docs).
 This is far from abstract a programmer from what's really happening. If  
 I code
 something like:

 void f(in int[10] x);

 Common sense will tell me that the 10 positions of my array are well  
 protected
 and they shouldn't be touched by 'f' and in return this isn't the  
 behavior.
I think everyone (including Walter) wants us to be able to do this sort of thing. Whether it's a good idea isn't really in doubt, what is, is how it can be implemented.
I thought I heared that Walter doesn't like the idea of const (that is definitely what in last instance we're talking about), because it can be circumvented with some black magic (or hackish coding). I didn't know he was up to implement that sort of thing (real 'in' parameters). Are you sure?
 Walter with all respect, this sucks! When will we have real protection
 attributes?
I suspect we'll have them as soon as Walter devises a way to implement them to his satisfaction.
Hope so.
 So the 'in' keyword for static arrays are perfectly useless and  
 introduces nothing (while in the background it is really "protecting"  
 the pointer to the first element -that doesn't need any protection-).
The 'in' keyword behaves the same way for arrays, classes and any other reference type, it protects the reference itself, not the data to which the reference refers.
Now that you've say it about a 100 times :-D, I ask: When would we have REAL PROTECION ATTRIBUTES FOR REFERENCED DATA RATHER THAN FOR REFERENCES ITSELF (readonly)? Regards, Tom;
Feb 22 2006
parent reply "Derek Parnell" <derek psych.ward> writes:
On Thu, 23 Feb 2006 01:30:34 +1100, Tom <Tom_member pathlink.com> wrote:


[snip]

 See the docs Derek posted in his last reply, 'in' does not promise to
 protect the data to which the array reference refers, only the array
 reference itself.
Sorry, I didn't understand Derek copied that from docs -in fact I can't find that in the docs [please guide me with a link if you do]-, but rather I think that is his own version of what he think the docs should state (or what has to be added to the docs).
Yes, they were my own words. You won't find them in the offical docs and that's the point I was trying to make. -- Derek Parnell Melbourne, Australia
Feb 22 2006
parent "Regan Heath" <regan netwin.co.nz> writes:
On Thu, 23 Feb 2006 02:29:18 +1100, Derek Parnell <derek psych.ward> wrote:
 On Thu, 23 Feb 2006 01:30:34 +1100, Tom <Tom_member pathlink.com> wrote:


 [snip]

 See the docs Derek posted in his last reply, 'in' does not promise to
 protect the data to which the array reference refers, only the array
 reference itself.
Sorry, I didn't understand Derek copied that from docs -in fact I can't find that in the docs [please guide me with a link if you do]-, but rather I think that is his own version of what he think the docs should state (or what has to be added to the docs).
Yes, they were my own words. You won't find them in the offical docs and that's the point I was trying to make.
My mistake. They were good words lets put them in the docs. Regan
Feb 22 2006