digitalmars.D.learn - Array as an argument, ambiguous behaviour.
- Cooler (14/14) Jan 29 2014 Consider 3 functions taking array as an argument:
- Tobias Pankrath (7/21) Jan 29 2014 Arrays are a pair of pointer and length.
- Cooler (2/2) Jan 29 2014 Thank you for detailed explanation. But the question is - "Is
- simendsjo (7/9) Jan 29 2014 Could you expand your example?
- Tobias Pankrath (2/4) Jan 29 2014 Where is it ambiguous?
- Cooler (11/15) Jan 29 2014 Ambiguity is here...
- simendsjo (12/28) Jan 29 2014 'in' is a shorthard for 'const scope'.
- Cooler (9/40) Jan 29 2014 Don't anybody understand me?!
- Dicebot (15/21) Jan 30 2014 You use very subjective meaning for "ambiguity", one that is
- Cooler (20/41) Jan 30 2014 If I use fun2() I expect that fun2() will change the content of
- Dicebot (2/6) Jan 30 2014 For changes to content of array but not array itself.
- Stanislav Blinov (2/5) Jan 30 2014 For zillion+nth time :)
- Cooler (5/11) Jan 30 2014 I agree. I just want that the case can be expressed in language
- Steven Schveighoffer (3/14) Jan 30 2014 That's what fun(int[] x) does :)
- Cooler (13/30) Jan 30 2014 Again...
- Tobias Pankrath (2/15) Jan 30 2014 It's [0, 0, 0, 0, 0, 0, 0, 0, 0, 0].
- Cooler (6/22) Jan 30 2014 No!!! It depends how runtime allocates memory for the array. Read
- Cooler (3/28) Jan 30 2014 Sorry!!! My mistake. The caller will see [0, 0, 0, 0, 0, 0, 0, 0,
- Cooler (4/33) Jan 30 2014 But that is the proof. The intention of fun() implementer will
- Steven Schveighoffer (8/38) Jan 30 2014 void foo(int x)
- Cooler (16/64) Jan 30 2014 Please understand - I am not against void foo(int[] x){}
- Steven Schveighoffer (18/39) Jan 30 2014 I thought that this meant you were against it?
- Cooler (12/53) Jan 30 2014 The language is needed to express your intentions to the
- Steven Schveighoffer (28/53) Jan 30 2014 Anything that the compiler cannot enforce is just documentation. Does it...
- Cooler (18/77) Jan 30 2014 I am telling to the compiler what to do, or what not to do, with
- Steven Schveighoffer (39/50) Jan 30 2014 const is only useful in cases where references are involved. In this cas...
- Maxim Fomin (42/67) Jan 30 2014 Predictability of behavior is not a principle of D and even if it
- Cooler (6/50) Jan 30 2014 Difference is here.
- Steven Schveighoffer (13/24) Jan 30 2014 This is incorrect:
- Steven Schveighoffer (16/39) Jan 30 2014 I suspect you mean:
- Sergei Nosov (10/26) Jan 29 2014 I believe you encounter an array reallocation.
- Cooler (10/15) Jan 29 2014 That exactly what am i asking for!
- Sergei Nosov (20/35) Jan 29 2014 E.g. you want fun3 to change the content of the array, but you
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (5/18) Jan 29 2014 Yes, that is how slices work in D. The following article explains the
- Cooler (6/10) Jan 29 2014 Thank you for the article.
- Tobias Pankrath (6/18) Jan 29 2014 It's not unpredictable, at least not more unpredictable then fun2.
- Cooler (11/17) Jan 29 2014 You don't understand me. You consider that I am author of the
- Tobias Pankrath (12/31) Jan 29 2014 Oh, I guess I understood quite well. I just don't see a special
- Cooler (4/37) Jan 29 2014 Do you read my post? I am answering... why do I need fun3() if I
- Tobias Pankrath (2/4) Jan 29 2014 fun3 guarantees that the argument has the same length for example.
- Cooler (5/11) Jan 29 2014 Where argument has the same length? After function call, or
- Stanislav Blinov (3/6) Jan 29 2014 Gosh. To allow the function to modify the contents, but not the
- Cooler (3/9) Jan 29 2014 Сам то понял чего написал??? :)
- Stanislav Blinov (2/13) Jan 29 2014 Yes I did.
- Tobias Pankrath (13/16) Jan 29 2014 Where argument has the same length? After function call, or
- Maxim Fomin (20/32) Jan 29 2014 If you want to modify the slice and make changes visible in
- Cooler (8/28) Jan 30 2014 Please stop explain me how fun3() works. I know that.
- Stanislav Blinov (9/17) Jan 30 2014 Goodness... You've been shown this use case like a zillion times
- Cooler (8/25) Jan 30 2014 May be I am dumb...
- Maxim Fomin (17/46) Jan 30 2014 This is first problem. You are being explained what is the
- Cooler (7/30) Jan 30 2014 Now I am trying to speak ideally. What ideal language should be,
- bearophile (12/15) Jan 30 2014 I think functions like void fun(int[] a){} are bug prone, because
- Cooler (8/23) Jan 30 2014 You wrote "this bug happened to me several times" :) This bug
- Maxim Fomin (11/17) Jan 30 2014 ...
- Cooler (3/22) Jan 30 2014 Agree. As a first step I post this topic in the forum. If I found
- Sergei Nosov (11/23) Jan 29 2014 This behavior is just a consequence of the deliberate decision on
- Cooler (2/12) Jan 29 2014 Ok! I agree with you! Can you just answer me
- Steven Schveighoffer (20/33) Jan 30 2014 Yes.
- Cooler (18/61) Jan 30 2014 If I don't want that fun() will change my array, i have to use
- Cooler (4/13) Jan 30 2014 "But I would point out that fun2 does not guarantee anything more
- Dicebot (6/9) Jan 30 2014 Unrelated.
- Steven Schveighoffer (4/18) Jan 30 2014 Which is false. That was my point.
- Steven Schveighoffer (19/32) Jan 30 2014 No. You can use fun3 variant as well:
- Jesse Phillips (4/18) Jan 30 2014 I believe what you are asking for is "head const." D does not do
Consider 3 functions taking array as an argument: void fun1(in int[] x){...} void fun2(ref int[] x){...} void fun3( int[] x){...} auto a = new int[10]; fun1(a); // Guaranteed that "a" will not be changed fun2(a); // Guaranteed that we will see any change to "a", made in fun2() fun3(a); // Changes to "a" in fun3() may be or may be not visible to the caller In case of fun3() we have ambiguous behaviour, depending on the body of the function. Am I right? Is that intentional?
Jan 29 2014
On Wednesday, 29 January 2014 at 10:55:57 UTC, Cooler wrote:Consider 3 functions taking array as an argument: void fun1(in int[] x){...} void fun2(ref int[] x){...} void fun3( int[] x){...} auto a = new int[10]; fun1(a); // Guaranteed that "a" will not be changed fun2(a); // Guaranteed that we will see any change to "a", made in fun2() fun3(a); // Changes to "a" in fun3() may be or may be not visible to the caller In case of fun3() we have ambiguous behaviour, depending on the body of the function. Am I right? Is that intentional?Arrays are a pair of pointer and length. fun1 marks the pointer, the length and the data pointed as const. fun3 marks nothing const, but since pointer and length are passed by value, you'll only see changes to the content of x. fun2 is like fun3, but pointer and length are itself passed by reference.
Jan 29 2014
Thank you for detailed explanation. But the question is - "Is that correct that language allows ambiguous behavior?"
Jan 29 2014
On Wednesday, 29 January 2014 at 11:46:23 UTC, Cooler wrote:Thank you for detailed explanation. But the question is - "Is that correct that language allows ambiguous behavior?"Could you expand your example? fun(int[] a) {} is passing a by value, that is, the pointer and length is copied over to fun. Any changes to the elements of a will be visible, but if you reassign a directly or indirectly (expanding it so it needs to be copied to a new memory location), the changes are not visible.
Jan 29 2014
On Wednesday, 29 January 2014 at 11:46:23 UTC, Cooler wrote:Thank you for detailed explanation. But the question is - "Is that correct that language allows ambiguous behavior?"Where is it ambiguous?
Jan 29 2014
On Wednesday, 29 January 2014 at 12:40:00 UTC, Tobias Pankrath wrote:On Wednesday, 29 January 2014 at 11:46:23 UTC, Cooler wrote:Ambiguity is here... When I call fun1() or fun2() I know the behavior directly from function signature (read the comments in my first post). For fun3() case the caller side don't know the behavior directly from function signature. To know what will happen with array "a", the caller must see to fun3() body. Ambiguity is - in first and second cases the caller knows what happens with "a", but in third case the caller does not know what happens with "a".Thank you for detailed explanation. But the question is - "Is that correct that language allows ambiguous behavior?"Where is it ambiguous?
Jan 29 2014
On Wednesday, 29 January 2014 at 13:15:30 UTC, Cooler wrote:On Wednesday, 29 January 2014 at 12:40:00 UTC, Tobias Pankrath wrote:'in' is a shorthard for 'const scope'. 'const' means that the callee cannot change the passed in parameter in any way, including anything available through that type (for example x[0]) 'scope' means it cannot leave the scope of the callee - that it cannot be stored away anywhere. 'ref' means that the parameter is passed by reference, and thus might be reassigned or changed in any way. No parameters means that it's mutable, but the reference cannot change. I don't see any ambiguities here.On Wednesday, 29 January 2014 at 11:46:23 UTC, Cooler wrote:Ambiguity is here... When I call fun1() or fun2() I know the behavior directly from function signature (read the comments in my first post). For fun3() case the caller side don't know the behavior directly from function signature. To know what will happen with array "a", the caller must see to fun3() body. Ambiguity is - in first and second cases the caller knows what happens with "a", but in third case the caller does not know what happens with "a".Thank you for detailed explanation. But the question is - "Is that correct that language allows ambiguous behavior?"Where is it ambiguous?
Jan 29 2014
On Wednesday, 29 January 2014 at 13:38:22 UTC, simendsjo wrote:On Wednesday, 29 January 2014 at 13:15:30 UTC, Cooler wrote:Don't anybody understand me?! I know what means "in" and "ref" qualifiers!On Wednesday, 29 January 2014 at 12:40:00 UTC, Tobias Pankrath wrote:'in' is a shorthard for 'const scope'. 'const' means that the callee cannot change the passed in parameter in any way, including anything available through that type (for example x[0]) 'scope' means it cannot leave the scope of the callee - that it cannot be stored away anywhere. 'ref' means that the parameter is passed by reference, and thus might be reassigned or changed in any way. No parameters means that it's mutable, but the reference cannot change. I don't see any ambiguities here.On Wednesday, 29 January 2014 at 11:46:23 UTC, Cooler wrote:Ambiguity is here... When I call fun1() or fun2() I know the behavior directly from function signature (read the comments in my first post). For fun3() case the caller side don't know the behavior directly from function signature. To know what will happen with array "a", the caller must see to fun3() body. Ambiguity is - in first and second cases the caller knows what happens with "a", but in third case the caller does not know what happens with "a".Thank you for detailed explanation. But the question is - "Is that correct that language allows ambiguous behavior?"Where is it ambiguous?No parameters means that it's mutable, but the reference cannot change.Here is ambiguity. void fun3(int[] x){ x ~= 5; ... } auto a = new int[10]; fun3(a); // Here content of "a" may be changed or may be not changed. Depends on the buffer size that system will allocate for "a" array.
Jan 29 2014
On Wednesday, 29 January 2014 at 14:34:54 UTC, Cooler wrote:Here is ambiguity. void fun3(int[] x){ x ~= 5; ... } auto a = new int[10]; fun3(a); // Here content of "a" may be changed or may be not changed. Depends on the buffer size that system will allocate for "a" array.You use very subjective meaning for "ambiguity", one that is never normally used in programming language context. Normally term "ambiguity" is applied only when _compiler_ can't reliably decide meaning of the code snippet and needs to resort to special casing. You are correct in notion that you can't make any reasonable judgement yourself about content of a after `fun3` call but same applies to `fun2` - it can be or not be modified. It is expected - to express all semantics of function body in function signature one would have needed to make it of comparable length and complexity. In practice you need always to assume the worst - everything is modified and nothing can be trusted unless explicitly qualified other way around.
Jan 30 2014
On Thursday, 30 January 2014 at 12:47:56 UTC, Dicebot wrote:On Wednesday, 29 January 2014 at 14:34:54 UTC, Cooler wrote:If I use fun2() I expect that fun2() will change the content of my array, and all changes I will see. If I don't want any change to my array, I will use fun1(). What should I want to use fun3()? As many people writes to me in the post - "You may want that fun3() change content of an array, but can't change length of array". I cannot imagine such use case. void fun3(int[] x){ x[0] = 5; x ~= 6; writeln(x); } // What caller will get? auto a = new int[10]; fun3(a); // What I must want here to call fun3(). If I want fun3() will change my array, I should prefer fun2() variant which will guarantee me that I will get all changes. If i just want send array to fun() for it internal use I should prefer fun1(). If I call fun3() the contents of array after the call is not predictable - it can be changed or may not. What must push me to use fun3()?Here is ambiguity. void fun3(int[] x){ x ~= 5; ... } auto a = new int[10]; fun3(a); // Here content of "a" may be changed or may be not changed. Depends on the buffer size that system will allocate for "a" array.You use very subjective meaning for "ambiguity", one that is never normally used in programming language context. Normally term "ambiguity" is applied only when _compiler_ can't reliably decide meaning of the code snippet and needs to resort to special casing. You are correct in notion that you can't make any reasonable judgement yourself about content of a after `fun3` call but same applies to `fun2` - it can be or not be modified. It is expected - to express all semantics of function body in function signature one would have needed to make it of comparable length and complexity.In practice you need always to assume the worst - everything is modified and nothing can be trusted unless explicitly qualified other way around.In practice if function declared as fun(in int[] a){} I can be sure that call fun(x) will not change 'x', until the compiler has a bug, or fun() author don't play with c-like pointers.
Jan 30 2014
On Thursday, 30 January 2014 at 13:42:53 UTC, Cooler wrote:If I use fun2() I expect that fun2() will change the content of my array, and all changes I will see. If I don't want any change to my array, I will use fun1(). What should I want to use fun3()?For changes to content of array but not array itself.
Jan 30 2014
On Thursday, 30 January 2014 at 14:40:36 UTC, Dicebot wrote:On Thursday, 30 January 2014 at 13:42:53 UTC, Cooler wrote:For zillion+nth time :)What should I want to use fun3()?For changes to content of array but not array itself.
Jan 30 2014
On Thursday, 30 January 2014 at 14:40:36 UTC, Dicebot wrote:On Thursday, 30 January 2014 at 13:42:53 UTC, Cooler wrote:I agree. I just want that the case can be expressed in language syntax more obvious - something like "fun(int[] const x){}" to emphasize that I understand that fun() can change content of array, and cannot change the {pointer,size} pair.If I use fun2() I expect that fun2() will change the content of my array, and all changes I will see. If I don't want any change to my array, I will use fun1(). What should I want to use fun3()?For changes to content of array but not array itself.
Jan 30 2014
On Thu, 30 Jan 2014 10:24:14 -0500, Cooler <kulkin hotbox.ru> wrote:On Thursday, 30 January 2014 at 14:40:36 UTC, Dicebot wrote:That's what fun(int[] x) does :) -SteveOn Thursday, 30 January 2014 at 13:42:53 UTC, Cooler wrote:I agree. I just want that the case can be expressed in language syntax more obvious - something like "fun(int[] const x){}" to emphasize that I understand that fun() can change content of array, and cannot change the {pointer,size} pair.If I use fun2() I expect that fun2() will change the content of my array, and all changes I will see. If I don't want any change to my array, I will use fun1(). What should I want to use fun3()?For changes to content of array but not array itself.
Jan 30 2014
On Thursday, 30 January 2014 at 15:29:50 UTC, Steven Schveighoffer wrote:On Thu, 30 Jan 2014 10:24:14 -0500, Cooler <kulkin hotbox.ru> wrote:Again... void fun(int[] x){ x ~= 5; } auto a = new int[10]; fun(a); // Can you predict the content of 'a'? In your case: void fun(int[] x){ x = [1, 2]; } // Compilation ok. Implementation's error. The fun() implementer made error and think that caller will get new array. But it will get it only at runtime! If we for example (just for example) have void fun(int[] const x){ x = [1, 2]; } // Compilation error.On Thursday, 30 January 2014 at 14:40:36 UTC, Dicebot wrote:That's what fun(int[] x) does :) -SteveOn Thursday, 30 January 2014 at 13:42:53 UTC, Cooler wrote:I agree. I just want that the case can be expressed in language syntax more obvious - something like "fun(int[] const x){}" to emphasize that I understand that fun() can change content of array, and cannot change the {pointer,size} pair.If I use fun2() I expect that fun2() will change the content of my array, and all changes I will see. If I don't want any change to my array, I will use fun1(). What should I want to use fun3()?For changes to content of array but not array itself.
Jan 30 2014
On Thursday, 30 January 2014 at 15:49:35 UTC, Cooler wrote:It's [0, 0, 0, 0, 0, 0, 0, 0, 0, 0].Again... void fun(int[] x){ x ~= 5; } auto a = new int[10]; fun(a); // Can you predict the content of 'a'?I agree. I just want that the case can be expressed in language syntax more obvious - something like "fun(int[] const x){}" to emphasize that I understand that fun() can change content of array, and cannot change the {pointer,size} pair.That's what fun(int[] x) does :) -Steve
Jan 30 2014
On Thursday, 30 January 2014 at 15:51:44 UTC, Tobias Pankrath wrote:On Thursday, 30 January 2014 at 15:49:35 UTC, Cooler wrote:No!!! It depends how runtime allocates memory for the array. Read http://dlang.org/d-array-article.html. If 'a' has internal space enough to place '5' the caller will see [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5].It's [0, 0, 0, 0, 0, 0, 0, 0, 0, 0].Again... void fun(int[] x){ x ~= 5; } auto a = new int[10]; fun(a); // Can you predict the content of 'a'?I agree. I just want that the case can be expressed in language syntax more obvious - something like "fun(int[] const x){}" to emphasize that I understand that fun() can change content of array, and cannot change the {pointer,size} pair.That's what fun(int[] x) does :) -Steve
Jan 30 2014
On Thursday, 30 January 2014 at 15:59:48 UTC, Cooler wrote:On Thursday, 30 January 2014 at 15:51:44 UTC, Tobias Pankrath wrote:Sorry!!! My mistake. The caller will see [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] :)On Thursday, 30 January 2014 at 15:49:35 UTC, Cooler wrote:No!!! It depends how runtime allocates memory for the array. Read http://dlang.org/d-array-article.html. If 'a' has internal space enough to place '5' the caller will see [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5].It's [0, 0, 0, 0, 0, 0, 0, 0, 0, 0].Again... void fun(int[] x){ x ~= 5; } auto a = new int[10]; fun(a); // Can you predict the content of 'a'?I agree. I just want that the case can be expressed in language syntax more obvious - something like "fun(int[] const x){}" to emphasize that I understand that fun() can change content of array, and cannot change the {pointer,size} pair.That's what fun(int[] x) does :) -Steve
Jan 30 2014
On Thursday, 30 January 2014 at 16:01:32 UTC, Cooler wrote:On Thursday, 30 January 2014 at 15:59:48 UTC, Cooler wrote:But that is the proof. The intention of fun() implementer will not be achieved. And such misunderstanding will appear only at runtime.On Thursday, 30 January 2014 at 15:51:44 UTC, Tobias Pankrath wrote:Sorry!!! My mistake. The caller will see [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] :)On Thursday, 30 January 2014 at 15:49:35 UTC, Cooler wrote:No!!! It depends how runtime allocates memory for the array. Read http://dlang.org/d-array-article.html. If 'a' has internal space enough to place '5' the caller will see [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5].It's [0, 0, 0, 0, 0, 0, 0, 0, 0, 0].Again... void fun(int[] x){ x ~= 5; } auto a = new int[10]; fun(a); // Can you predict the content of 'a'?I agree. I just want that the case can be expressed in language syntax more obvious - something like "fun(int[] const x){}" to emphasize that I understand that fun() can change content of array, and cannot change the {pointer,size} pair.That's what fun(int[] x) does :) -Steve
Jan 30 2014
On Thu, 30 Jan 2014 11:04:44 -0500, Cooler <kulkin hotbox.ru> wrote:On Thursday, 30 January 2014 at 16:01:32 UTC, Cooler wrote:void foo(int x) { x = 5; } "hey, why doesn't that work! Setting a parameter to another value should be illegal!" -SteveOn Thursday, 30 January 2014 at 15:59:48 UTC, Cooler wrote:But that is the proof. The intention of fun() implementer will not be achieved. And such misunderstanding will appear only at runtime.On Thursday, 30 January 2014 at 15:51:44 UTC, Tobias Pankrath wrote:Sorry!!! My mistake. The caller will see [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] :)On Thursday, 30 January 2014 at 15:49:35 UTC, Cooler wrote:No!!! It depends how runtime allocates memory for the array. Read http://dlang.org/d-array-article.html. If 'a' has internal space enough to place '5' the caller will see [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5].It's [0, 0, 0, 0, 0, 0, 0, 0, 0, 0].Again... void fun(int[] x){ x ~= 5; } auto a = new int[10]; fun(a); // Can you predict the content of 'a'?I agree. I just want that the case can be expressed in language syntax more obvious - something like "fun(int[] const x){}" to emphasize that I understand that fun() can change content of array, and cannot change the {pointer,size} pair.That's what fun(int[] x) does :) -Steve
Jan 30 2014
On Thursday, 30 January 2014 at 16:18:33 UTC, Steven Schveighoffer wrote:On Thu, 30 Jan 2014 11:04:44 -0500, Cooler <kulkin hotbox.ru> wrote:Please understand - I am not against void foo(int[] x){} I am for predictability of behavior. You suggest to describe function's behavior in documentation - quotation from your article "It is a good idea to note in the documentation how the passed in slice might or might not be overwritten." My idea is that all potential errors must be detected as soon as possible. The D principle - "The program compile and runs as expected, or not compile at all". If you really need to call function that can change content of an array, but cannot change size of an array the language syntax should allow express it in function signature. I consider "void fun(int[] const x){}" more error prone than "void fun(int[] x){}" and for the caller and for implemeter.On Thursday, 30 January 2014 at 16:01:32 UTC, Cooler wrote:void foo(int x) { x = 5; } "hey, why doesn't that work! Setting a parameter to another value should be illegal!" -SteveOn Thursday, 30 January 2014 at 15:59:48 UTC, Cooler wrote:But that is the proof. The intention of fun() implementer will not be achieved. And such misunderstanding will appear only at runtime.On Thursday, 30 January 2014 at 15:51:44 UTC, Tobias Pankrath wrote:Sorry!!! My mistake. The caller will see [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] :)On Thursday, 30 January 2014 at 15:49:35 UTC, Cooler wrote:No!!! It depends how runtime allocates memory for the array. Read http://dlang.org/d-array-article.html. If 'a' has internal space enough to place '5' the caller will see [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5].It's [0, 0, 0, 0, 0, 0, 0, 0, 0, 0].Again... void fun(int[] x){ x ~= 5; } auto a = new int[10]; fun(a); // Can you predict the content of 'a'?I agree. I just want that the case can be expressed in language syntax more obvious - something like "fun(int[] const x){}" to emphasize that I understand that fun() can change content of array, and cannot change the {pointer,size} pair.That's what fun(int[] x) does :) -SteveI see very little value in that. We don't need to obliterate a tremendous amount of slice usage (not mentioning how much code will have to be updated) in order to help newbies understand how slices work.Any idea can be rejected by this sentence.
Jan 30 2014
On Thu, 30 Jan 2014 11:48:50 -0500, Cooler <kulkin hotbox.ru> wrote:Please understand - I am not against void foo(int[] x){}From an earlier post by you:May be just prohibit at language level the case of fun3() function, to do not allow unpredictable behavior?I thought that this meant you were against it?I am for predictability of behavior. You suggest to describe function's behavior in documentation - quotation from your article "It is a good idea to note in the documentation how the passed in slice might or might not be overwritten." My idea is that all potential errors must be detected as soon as possible.You cannot eradicate all errors. The intentions of a function are not apparent to the compiler. Maybe the intention is to use the argument as a buffer, and the caller should not care what happens to the buffer inside the function. Adding yet another attribute is going to increase language complexity for almost no benefit. It does not guarantee unambiguity because you have no idea what the author of the function is going to do.The D principle - "The program compile and runs as expected, or not compile at all".This is a fantasy. The compiler cannot know what you expect.If you really need to call function that can change content of an array, but cannot change size of an array the language syntax should allow express it in function signature. I consider "void fun(int[] const x){}" more error prone than "void fun(int[] x){}" and for the caller and for implemeter.Not sure if something is mixed up there. I think void fun(int[] x) is sufficient to describe what you say. The function cannot alter x's array bounds at all, and can alter it's data.No, only ideas that force people to change millions of lines of code, and provide scant benefits instead of taking 5 minutes to explain "no, just use x[0..2] = [1, 2]" or "just use ref int[] x" depending on the goal. -SteveI see very little value in that. We don't need to obliterate a tremendous amount of slice usage (not mentioning how much code will have to be updated) in order to help newbies understand how slices work.Any idea can be rejected by this sentence.
Jan 30 2014
That was the question with "May be..." at the beginning.Please understand - I am not against void foo(int[] x){}From an earlier post by you:May be just prohibit at language level the case of fun3() function, to do not allow unpredictable behavior?I thought that this meant you were against it?The language is needed to express your intentions to the compiler. The language should be expressive as possible. My point is to push programmers to write correct software. I just ask these forum to think about topic. If everybody satisfied by void fun(int[] x){} behavior, then I just go... But I encounter a bug in my program that was due to my misusing of such signature.I am for predictability of behavior. You suggest to describe function's behavior in documentation - quotation from your article "It is a good idea to note in the documentation how the passed in slice might or might not be overwritten." My idea is that all potential errors must be detected as soon as possible.You cannot eradicate all errors. The intentions of a function are not apparent to the compiler. Maybe the intention is to use the argument as a buffer, and the caller should not care what happens to the buffer inside the function. Adding yet another attribute is going to increase language complexity for almost no benefit. It does not guarantee unambiguity because you have no idea what the author of the function is going to do.The D principle - "The program compile and runs as expected, or not compile at all".This is a fantasy. The compiler cannot know what you expect.Here is the reason why i post the topic on this forum. You think one way, I think another way. I wanted to discuss what think other people. But looks like still nobody can understand my point, or may be I cannot express it...If you really need to call function that can change content of an array, but cannot change size of an array the language syntax should allow express it in function signature. I consider "void fun(int[] const x){}" more error prone than "void fun(int[] x){}" and for the caller and for implemeter.Not sure if something is mixed up there. I think void fun(int[] x) is sufficient to describe what you say. The function cannot alter x's array bounds at all, and can alter it's data.No, only ideas that force people to change millions of lines of code, and provide scant benefits instead of taking 5 minutes to explain "no, just use x[0..2] = [1, 2]" or "just use ref int[] x" depending on the goal. -SteveI see very little value in that. We don't need to obliterate a tremendous amount of slice usage (not mentioning how much code will have to be updated) in order to help newbies understand how slices work.Any idea can be rejected by this sentence.
Jan 30 2014
On Thu, 30 Jan 2014 12:38:57 -0500, Cooler <kulkin hotbox.ru> wrote:Anything that the compiler cannot enforce is just documentation. Does it matter whether the documentation is in a comment or part of the signature?The language is needed to express your intentions to the compiler.The D principle - "The program compile and runs as expected, or not compile at all".This is a fantasy. The compiler cannot know what you expect.The language should be expressive as possible. My point is to push programmers to write correct software. I just ask these forum to think about topic. If everybody satisfied by void fun(int[] x){} behavior, then I just go...I'm not trying to be a bully or anything, but you are not understanding that what you want is a guarantee of logic, that the compiler cannot possibly enforce. Your example (setting a variable to another value) being rejected is easy to work around, just use another variable that doesn't have that restriction. There are so many examples of behavior-enforcing features that result in something that the creator of the feature didn't want or expect. Keep in mind there are years of projects that have been written assuming that you can use a standard slice in the signature of a function, we don't want to invalidate all that code just because programmers sometimes write buggy code.But I encounter a bug in my program that was due to my misusing of such signature.Here's where the gray area is. If you make this error once or twice, but never again, is it worth changing the language over? Probably not. But if you make this error every day, even KNOWING what will happen, it's worth looking into. But any changes have to avoid a negative impact on existing code as much as possible. Think of the person who knows how slices work, who very seldom makes this mistake, and who now has to go through all his code and make this change, never finding an instance where it makes a difference. At this point, I'm not sure what you are proposing, but I don't think there is much value in changing the way slice passing works.By mixed up, I meant that you seemed to be valuing the int[] x version over the int[] const x version. Other than that, what I stated is an indisputable fact -- the function cannot alter x's bounds. -SteveHere is the reason why i post the topic on this forum. You think one way, I think another way. I wanted to discuss what think other people. But looks like still nobody can understand my point, or may be I cannot express it...If you really need to call function that can change content of an array, but cannot change size of an array the language syntax should allow express it in function signature. I consider "void fun(int[] const x){}" more error prone than "void fun(int[] x){}" and for the caller and for implemeter.Not sure if something is mixed up there. I think void fun(int[] x) is sufficient to describe what you say. The function cannot alter x's array bounds at all, and can alter it's data.
Jan 30 2014
Why we need "const" keyword, while we can just put "I promise do not change it" in the documentation?Anything that the compiler cannot enforce is just documentation. Does it matter whether the documentation is in a comment or part of the signature?The language is needed to express your intentions to the compiler.The D principle - "The program compile and runs as expected, or not compile at all".This is a fantasy. The compiler cannot know what you expect.I am telling to the compiler what to do, or what not to do, with help of programming language. I am controlling the compilation result with the language. I am not waiting that compiler will anticipate my thoughts. But if I write "const x" the variable must be const. If i have language construct that can give me stronger guarantees, i will use it.The language should be expressive as possible. My point is to push programmers to write correct software. I just ask these forum to think about topic. If everybody satisfied by void fun(int[] x){} behavior, then I just go...I'm not trying to be a bully or anything, but you are not understanding that what you want is a guarantee of logic, that the compiler cannot possibly enforce.Your example (setting a variable to another value) being rejected is easy to work around, just use another variable that doesn't have that restriction.My goal is not to implement some functionality, and I don't know how to do it. I want to make programmer's intentions more clear with a help of language. What you are saying is approximately - "If everybody will tune the language to his private needs, it will be not good". I agree with such point. Therefore I asked in the forum - am I alone who wants to tune this language feature? If you are experienced programmer in D your brain filter such cases automatically.There are so many examples of behavior-enforcing features that result in something that the creator of the feature didn't want or expect. Keep in mind there are years of projects that have been written assuming that you can use a standard slice in the signature of a function, we don't want to invalidate all that code just because programmers sometimes write buggy code.I don't even thought to invalidate already written code.But I encounter a bug in my program that was due to my misusing of such signature.Here's where the gray area is. If you make this error once or twice, but never again, is it worth changing the language over? Probably not. But if you make this error every day, even KNOWING what will happen, it's worth looking into. But any changes have to avoid a negative impact on existing code as much as possible. Think of the person who knows how slices work, who very seldom makes this mistake, and who now has to go through all his code and make this change, never finding an instance where it makes a difference. At this point, I'm not sure what you are proposing, but I don't think there is much value in changing the way slice passing works.By mixed up, I meant that you seemed to be valuing the int[] x version over the int[] const x version. Other than that, what I stated is an indisputable fact -- the function cannot alter x's bounds. -SteveHere is the reason why i post the topic on this forum. You think one way, I think another way. I wanted to discuss what think other people. But looks like still nobody can understand my point, or may be I cannot express it...If you really need to call function that can change content of an array, but cannot change size of an array the language syntax should allow express it in function signature. I consider "void fun(int[] const x){}" more error prone than "void fun(int[] x){}" and for the caller and for implemeter.Not sure if something is mixed up there. I think void fun(int[] x) is sufficient to describe what you say. The function cannot alter x's array bounds at all, and can alter it's data.
Jan 30 2014
On Thu, 30 Jan 2014 13:58:55 -0500, Cooler <kulkin hotbox.ru> wrote:const is only useful in cases where references are involved. In this case, you want to make the *copied* data constant, in hopes that you then can't accidentally stop referencing the original. In another example, there is little to be gained from a signature such as: void foo(const int x); What does this say about foo? Nothing. I can pass in a mutable, const, or immutable int, because a copy is made. It doesn't provide any more guarantees to the caller than: void foo(int x); Likewise, your proposed "int[] const" would not guarantee anything extra to the caller beyond "int[]", because both are copies put onto the stack. The function has no access to the original values. Arrays in D are hard to understand. They don't behave like arrays in most other languages. But they foster a different mindset I think, that results in some of the fastest code on the planet. But one has to understand the semantics of syntax if they want to properly use the language. For functions which append/extend and then write data to the prior piece (the only non-deterministic case), special care has to be taken to explain this to the caller. I would think a mechanism to attempt detecting this and flagging it would be a worthy lint tool feature. But not a language or compiler feature. There is just simply no way to say "that is always bad" or that you know what the intentions of the author are. The other case you specified, when the author re-assigns a slice and expects it to be a memcpy or to re-bind the calling parameter, the result is deterministically the wrong result, and the coder will notice it right away (and hopefully correct their understanding). I don't think we need a language feature for that, just documentation (which I think we have). Let me also suggest you use scope statements to verify at runtime that the case you intend to prevent doesn't actually happen: void foo(int[] x) { const origx = x; scope(exit) assert(origx.ptr == x.ptr); ... } While not perfect, and not static, it should at least avoid subtle bugs (and can be turned off in release mode). -SteveWhy we need "const" keyword, while we can just put "I promise do not change it" in the documentation?Anything that the compiler cannot enforce is just documentation. Does it matter whether the documentation is in a comment or part of the signature?The language is needed to express your intentions to the compiler.The D principle - "The program compile and runs as expected, or not compile at all".This is a fantasy. The compiler cannot know what you expect.
Jan 30 2014
On Thursday, 30 January 2014 at 16:48:51 UTC, Cooler wrote:On Thursday, 30 January 2014 at 16:18:33 UTC, Steven Schveighoffer wrote:Predictability of behavior is not a principle of D and even if it would be, it can't be applied blindly. D is not a formal mathematic system.void foo(int x) { x = 5; } "hey, why doesn't that work! Setting a parameter to another value should be illegal!" -StevePlease understand - I am not against void foo(int[] x){} I am for predictability of behavior.You suggest to describe function's behavior in documentation - quotation from your article "It is a good idea to note in the documentation how the passed in slice might or might not be overwritten." My idea is that all potential errors must be detected as soon as possible.It is impossible to detect all errors in D per se, let alone taking into account separate compilation model. In some circumstances compiler can guess possible ways, but particular case we discussing is so common, that nothing can be done to 'fix' it. By the way, this case is not strictly speaking an error. It is error in context when caller cares about changes but this can be hardly verified at compile time (compiler need to read brain to know it).The D principle - "The program compile and runs as expected, or not compile at all".It is all talk. Trying to apply this 'principle' in all cases is too naive.If you really need to call function that can change content of an array, but cannot change size of an array the language syntax should allow express it in function signature. I consider "void fun(int[] const x){}" more error prone than "void fun(int[] x){}" and for the caller and for implemeter.Personally this syntax is awful. By the way, there is another similar issue in D: import std.stdio; void foo(int[int] aa) { aa[1] = 1; } void main() { int[int] aa; foo(aa); writeln(aa); // [] aa[0] = 0; foo(aa); writeln(aa); // [0:0, 1:1] aa = null; foo(aa); writeln(aa); // [] } Here changes in AA array will be visible conditional that array is non null. If it is null, changes will be lost. This is another example of situation of "the caller MAY or MAY NOT see changes to" (citing your post above). In general, such semivalue-semireference semantic is produced when there is pointer wrapped into struct (doesn't matter whether it is opaque lang type or user defined). This happens in some language types, but may be also in user defined types. I don't think that verifying arbitrary semantic is compiler job.
Jan 30 2014
On Thursday, 30 January 2014 at 16:18:33 UTC, Steven Schveighoffer wrote:On Thu, 30 Jan 2014 11:04:44 -0500, Cooler <kulkin hotbox.ru> wrote:Difference is here. "void foo(int x){}" - the caller will NEVER see any change to 'x'. "void foo(int[] x){}" - the caller MAY or MAY NOT see changes to 'x'.On Thursday, 30 January 2014 at 16:01:32 UTC, Cooler wrote:void foo(int x) { x = 5; } "hey, why doesn't that work! Setting a parameter to another value should be illegal!" -SteveOn Thursday, 30 January 2014 at 15:59:48 UTC, Cooler wrote:But that is the proof. The intention of fun() implementer will not be achieved. And such misunderstanding will appear only at runtime.On Thursday, 30 January 2014 at 15:51:44 UTC, Tobias Pankrath wrote:Sorry!!! My mistake. The caller will see [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] :)On Thursday, 30 January 2014 at 15:49:35 UTC, Cooler wrote:No!!! It depends how runtime allocates memory for the array. Read http://dlang.org/d-array-article.html. If 'a' has internal space enough to place '5' the caller will see [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5].It's [0, 0, 0, 0, 0, 0, 0, 0, 0, 0].Again... void fun(int[] x){ x ~= 5; } auto a = new int[10]; fun(a); // Can you predict the content of 'a'?I agree. I just want that the case can be expressed in language syntax more obvious - something like "fun(int[] const x){}" to emphasize that I understand that fun() can change content of array, and cannot change the {pointer,size} pair.That's what fun(int[] x) does :) -Steve
Jan 30 2014
On Thu, 30 Jan 2014 12:07:07 -0500, Cooler <kulkin hotbox.ru> wrote:On Thursday, 30 January 2014 at 16:18:33 UTC, Steven Schveighoffer wrote:This is incorrect: foo(int[] x){} - The caller will see changes to data 'x' references. A slice is a reference type, it references a specific block of data. It's more akin to a pointer than an int. I could change my example: void foo(int *x) { int n = 3; x = &n; } "hey, why doesn't x now point to 3? Should be illegal!" -Stevevoid foo(int x) { x = 5; } "hey, why doesn't that work! Setting a parameter to another value should be illegal!"Difference is here. "void foo(int x){}" - the caller will NEVER see any change to 'x'. "void foo(int[] x){}" - the caller MAY or MAY NOT see changes to 'x'.
Jan 30 2014
On Thu, 30 Jan 2014 10:49:34 -0500, Cooler <kulkin hotbox.ru> wrote:On Thursday, 30 January 2014 at 15:29:50 UTC, Steven Schveighoffer wrote:On Thu, 30 Jan 2014 10:24:14 -0500, Cooler <kulkin hotbox.ru> wrote:On Thursday, 30 January 2014 at 14:40:36 UTC, Dicebot wrote:I suspect you mean: void fun(int[] x) {x.length += 1; x[0] = 5;} I cannot predict what the caller will see. But this is not a problem of *signatures*. The caller will not see ANY changes to {pointer,size} pair of x. That is the point -- it's passed by value. Note that this implementation is completely predictable: void fun(int[] x) {x[0] = 5; x.length += 1;} I want to stress that just because you can find an implementation that has a bug doesn't mean that there is an opportunity for the compiler to detect that bug, especially a logic bug. The compiler simply cannot know what you are thinking.Again... void fun(int[] x){ x ~= 5; } auto a = new int[10]; fun(a); // Can you predict the content of 'a'?I agree. I just want that the case can be expressed in language syntax more obvious - something like "fun(int[] const x){}" to emphasize that I understand that fun() can change content of array, and cannot change the {pointer,size} pair.That's what fun(int[] x) does :) -SteveIn your case: void fun(int[] x){ x = [1, 2]; } // Compilation ok. Implementation's error. The fun() implementer made error and think that caller will get new array. But it will get it only at runtime! If we for example (just for example) have void fun(int[] const x){ x = [1, 2]; } // Compilation error.I see very little value in that. We don't need to obliterate a tremendous amount of slice usage (not mentioning how much code will have to be updated) in order to help newbies understand how slices work. -Steve
Jan 30 2014
On Wednesday, 29 January 2014 at 13:15:30 UTC, Cooler wrote:On Wednesday, 29 January 2014 at 12:40:00 UTC, Tobias Pankrath wrote:I believe you encounter an array reallocation. If fun3 doesn't change the size of the array - you will see every change made by fun3 to the contents of `a` (but the `a` itself cannot be changed - only the contents). No other way around. If, however, in fun3 you change the size of the array - it may reallocate. Like, if you're appending to `x` - it will allocate a new array and make x point to it. Now `a` and `x` point to distinct arrays. And any change you do using `x` won't be seen by `a`. And, yes, this is the intended behavior.On Wednesday, 29 January 2014 at 11:46:23 UTC, Cooler wrote:Ambiguity is here... When I call fun1() or fun2() I know the behavior directly from function signature (read the comments in my first post). For fun3() case the caller side don't know the behavior directly from function signature. To know what will happen with array "a", the caller must see to fun3() body. Ambiguity is - in first and second cases the caller knows what happens with "a", but in third case the caller does not know what happens with "a".Thank you for detailed explanation. But the question is - "Is that correct that language allows ambiguous behavior?"Where is it ambiguous?
Jan 29 2014
If, however, in fun3 you change the size of the array - it may reallocate. Like, if you're appending to `x` - it will allocate a new array and make x point to it. Now `a` and `x` point to distinct arrays. And any change you do using `x` won't be seen by `a`. And, yes, this is the intended behavior.That exactly what am i asking for! You have to know the body of fun3() to predict what happened with 'a'. When I call fun() there are 3 intentions: 1. I want just send the contents of 'a' to fun(). It can be done by a.dup, or you must sure that fun() has 'in' qualifier for it's argument. 2. I want fun() change content of 'a' array. This can be done by ensuring fun() has 'ref' qualifier for it's argument. What intention should I have to call fun3()?
Jan 29 2014
On Wednesday, 29 January 2014 at 14:48:12 UTC, Cooler wrote:E.g. you want fun3 to change the content of the array, but you don't want it to change the pointer. Consider, void fun2(ref int[] x) { x = null; } void fun3(int[] x) { x = null; } void main() { int[] a = [1, 2, 3]; fun3(a); assert(a); fun2(a); assert(!a); }If, however, in fun3 you change the size of the array - it may reallocate. Like, if you're appending to `x` - it will allocate a new array and make x point to it. Now `a` and `x` point to distinct arrays. And any change you do using `x` won't be seen by `a`. And, yes, this is the intended behavior.That exactly what am i asking for! You have to know the body of fun3() to predict what happened with 'a'. When I call fun() there are 3 intentions: 1. I want just send the contents of 'a' to fun(). It can be done by a.dup, or you must sure that fun() has 'in' qualifier for it's argument. 2. I want fun() change content of 'a' array. This can be done by ensuring fun() has 'ref' qualifier for it's argument. What intention should I have to call fun3()?
Jan 29 2014
On 01/29/2014 02:55 AM, Cooler wrote:Consider 3 functions taking array as an argument: void fun1(in int[] x){...} void fun2(ref int[] x){...} void fun3( int[] x){...} auto a = new int[10]; fun1(a); // Guaranteed that "a" will not be changed fun2(a); // Guaranteed that we will see any change to "a", made in fun2() fun3(a); // Changes to "a" in fun3() may be or may be not visible to the caller In case of fun3() we have ambiguous behaviour, depending on the body of the function. Am I right? Is that intentional?Yes, that is how slices work in D. The following article explains the "non-determinism" that you mention: http://dlang.org/d-array-article.html Ali
Jan 29 2014
Yes, that is how slices work in D. The following article explains the "non-determinism" that you mention: http://dlang.org/d-array-article.html AliThank you for the article. Quotation from the article "It is a good idea to note in the documentation how the passed in slice might or might not be overwritten." May be just prohibit at language level the case of fun3() function, to do not allow unpredictable behavior?
Jan 29 2014
On Wednesday, 29 January 2014 at 15:11:33 UTC, Cooler wrote:It's not unpredictable, at least not more unpredictable then fun2. Should we dissallow this two? int[] a = [1,2,3,4]; b = a; b ~= [5, 6, 7, 8];Yes, that is how slices work in D. The following article explains the "non-determinism" that you mention: http://dlang.org/d-array-article.html AliThank you for the article. Quotation from the article "It is a good idea to note in the documentation how the passed in slice might or might not be overwritten." May be just prohibit at language level the case of fun3() function, to do not allow unpredictable behavior?
Jan 29 2014
It's not unpredictable, at least not more unpredictable then fun2. Should we dissallow this two? int[] a = [1,2,3,4]; b = a; b ~= [5, 6, 7, 8];You don't understand me. You consider that I am author of the fun() and the caller side. Read two post above http://forum.dlang.org/post/dxqxlhyhmdfuashhmtrz forum.dlang.org I consider that author of fun() and author of caller side are different persons. They must agree between them how to provide some functionality. If I fun()'s author why do I need to provide fun3() if I already provided fun1() and fun2()? I I caller's author - why may I require fun3() variant, if I already have fun1() and fun2()?
Jan 29 2014
On Wednesday, 29 January 2014 at 15:38:34 UTC, Cooler wrote:Oh, I guess I understood quite well. I just don't see a special problem with arrays, it's just the same as any other aliasing issue. Take this for example: void funS(S* s); // S is a struct, maybe containing a ptr and a length member :-) Should we disallow this as well? When I give a unqualified pointer to a function, the only guarantee I get is that it's pointing to the same location after the call. It's the same with arrays. And since we have this problem every time we pass a pointer to function I don't see why arrays should get special treatment.It's not unpredictable, at least not more unpredictable then fun2. Should we dissallow this two? int[] a = [1,2,3,4]; b = a; b ~= [5, 6, 7, 8];You don't understand me. You consider that I am author of the fun() and the caller side. Read two post above http://forum.dlang.org/post/dxqxlhyhmdfuashhmtrz forum.dlang.org I consider that author of fun() and author of caller side are different persons. They must agree between them how to provide some functionality. If I fun()'s author why do I need to provide fun3() if I already provided fun1() and fun2()? I I caller's author - why may I require fun3() variant, if I already have fun1() and fun2()?
Jan 29 2014
On Wednesday, 29 January 2014 at 15:56:50 UTC, Tobias Pankrath wrote:On Wednesday, 29 January 2014 at 15:38:34 UTC, Cooler wrote:Do you read my post? I am answering... why do I need fun3() if I already have fun1() and fun2().Oh, I guess I understood quite well. I just don't see a special problem with arrays, it's just the same as any other aliasing issue. Take this for example: void funS(S* s); // S is a struct, maybe containing a ptr and a length member :-) Should we disallow this as well? When I give a unqualified pointer to a function, the only guarantee I get is that it's pointing to the same location after the call. It's the same with arrays. And since we have this problem every time we pass a pointer to function I don't see why arrays should get special treatment.It's not unpredictable, at least not more unpredictable then fun2. Should we dissallow this two? int[] a = [1,2,3,4]; b = a; b ~= [5, 6, 7, 8];You don't understand me. You consider that I am author of the fun() and the caller side. Read two post above http://forum.dlang.org/post/dxqxlhyhmdfuashhmtrz forum.dlang.org I consider that author of fun() and author of caller side are different persons. They must agree between them how to provide some functionality. If I fun()'s author why do I need to provide fun3() if I already provided fun1() and fun2()? I I caller's author - why may I require fun3() variant, if I already have fun1() and fun2()?
Jan 29 2014
On Wednesday, 29 January 2014 at 16:01:08 UTC, Cooler wrote:Do you read my post? I am answering... why do I need fun3() if I already have fun1() and fun2().fun3 guarantees that the argument has the same length for example.
Jan 29 2014
On Wednesday, 29 January 2014 at 16:15:36 UTC, Tobias Pankrath wrote:On Wednesday, 29 January 2014 at 16:01:08 UTC, Cooler wrote:Where argument has the same length? After function call, or inside function? I don't understand what my intention should be to push me to use fun3()?Do you read my post? I am answering... why do I need fun3() if I already have fun1() and fun2().fun3 guarantees that the argument has the same length for example.
Jan 29 2014
On Wednesday, 29 January 2014 at 16:26:05 UTC, Cooler wrote:Where argument has the same length? After function call, or inside function? I don't understand what my intention should be to push me to use fun3()?Gosh. To allow the function to modify the contents, but not the size of the array.
Jan 29 2014
On Wednesday, 29 January 2014 at 16:36:44 UTC, Stanislav Blinov wrote:On Wednesday, 29 January 2014 at 16:26:05 UTC, Cooler wrote:Сам то понял чего написал??? :)Where argument has the same length? After function call, or inside function? I don't understand what my intention should be to push me to use fun3()?Gosh. To allow the function to modify the contents, but not the size of the array.
Jan 29 2014
On Wednesday, 29 January 2014 at 16:54:27 UTC, Cooler wrote:On Wednesday, 29 January 2014 at 16:36:44 UTC, Stanislav Blinov wrote:Yes I did.On Wednesday, 29 January 2014 at 16:26:05 UTC, Cooler wrote:Сам то понял чего написал??? :)Where argument has the same length? After function call, or inside function? I don't understand what my intention should be to push me to use fun3()?Gosh. To allow the function to modify the contents, but not the size of the array.
Jan 29 2014
On Wednesday, 29 January 2014 at 16:26:05 UTC, Cooler wrote:Where argument has the same length? After function call, or inside function? I don't understand what my intention should be to push me to use fun3()?Where argument has the same length? After function call, or inside function? I don't understand what my intention should be to push me to use fun3()? int[] a = [1,2,3]; // length == 3 fun3(a); assert(a.length == 3); // holds. If you have fun1 and fun2 you might have no use case for fun3. That is however no reason to disallow fun3, especially since there are situations where you don't won't to have fun2. Keep in mind, that I'm only arguing against a ban of fun3 and the notion that it's behaviour is more unpredictable then fun2 although it offers stronger guarantees.
Jan 29 2014
On Wednesday, 29 January 2014 at 16:26:05 UTC, Cooler wrote:On Wednesday, 29 January 2014 at 16:15:36 UTC, Tobias Pankrath wrote:If you want to modify the slice and make changes visible in caller, you should use ref. If you don't care whether changes are visible in caller, you can omit any attributes and use plain array. This belongs to the case you are asking about. If you don't want to change array in callee, pass it as const qualified. Now, after rethinking the issue I am inclining that "don't care whether changes are visible for caller" is not very wrong, but not very good design. Ideally it should be specified to avoid unexpected problems to pop up. So yes, it is better to qualify array. Another point. This casino games of whether changes would be visible or not is direct consequence of how slices are implemented (and how runtime service them). Remember, that many features in D work in a strange way not because of wise design but as a consequence of not fully thought design (like array). As a result, some features work in not best way they should. Although many folks in newsgroups would eagerly say that you don't understand the lang, it wouldn't make a bad design a good one.On Wednesday, 29 January 2014 at 16:01:08 UTC, Cooler wrote:Where argument has the same length? After function call, or inside function? I don't understand what my intention should be to push me to use fun3()?Do you read my post? I am answering... why do I need fun3() if I already have fun1() and fun2().fun3 guarantees that the argument has the same length for example.
Jan 29 2014
If you want to modify the slice and make changes visible in caller, you should use ref. If you don't care whether changes are visible in caller, you can omit any attributes and use plain array. This belongs to the case you are asking about. If you don't want to change array in callee, pass it as const qualified. Now, after rethinking the issue I am inclining that "don't care whether changes are visible for caller" is not very wrong, but not very good design. Ideally it should be specified to avoid unexpected problems to pop up. So yes, it is better to qualify array. Another point. This casino games of whether changes would be visible or not is direct consequence of how slices are implemented (and how runtime service them). Remember, that many features in D work in a strange way not because of wise design but as a consequence of not fully thought design (like array). As a result, some features work in not best way they should. Although many folks in newsgroups would eagerly say that you don't understand the lang, it wouldn't make a bad design a good one.Please stop explain me how fun3() works. I know that. One of the main idea of D is that things must work as planned, or would not compile at all. First and second variants follow this idea. But fun3() can work not as planned on the caller side (depends on fun3() body's implementation). The question again - may be prohibit fun3() variant? If we prohibit it, what use cases we could not implement with fun1() and fun2()?
Jan 30 2014
On Thursday, 30 January 2014 at 09:14:43 UTC, Cooler wrote:Please stop explain me how fun3() works. I know that. One of the main idea of D is that things must work as planned, or would not compile at all. First and second variants follow this idea. But fun3() can work not as planned on the caller side (depends on fun3() body's implementation). The question again - may be prohibit fun3() variant? If we prohibit it, what use cases we could not implement with fun1() and fun2()?Goodness... You've been shown this use case like a zillion times already: the caller manages her buffer, fun3() is allowed to change contents, but not reallocate caller's buffer. fun1() can't provide that (const), fun2() cannot either, because it explicitly allows reallocation (ref). This behavior is only provided by fun3(). So it's either that, or indeed cases of "I don't care about this array", which Maxim Fomin has mentioned.
Jan 30 2014
On Thursday, 30 January 2014 at 09:26:56 UTC, Stanislav Blinov wrote:On Thursday, 30 January 2014 at 09:14:43 UTC, Cooler wrote:May be I am dumb... If "I don't care about this array", I can use any of fun1() or fun2(). Can you formulate contract to fun3()? Something like "Change content of an array, but if you need to change the size - don't do it!" Do you think so?Please stop explain me how fun3() works. I know that. One of the main idea of D is that things must work as planned, or would not compile at all. First and second variants follow this idea. But fun3() can work not as planned on the caller side (depends on fun3() body's implementation). The question again - may be prohibit fun3() variant? If we prohibit it, what use cases we could not implement with fun1() and fun2()?Goodness... You've been shown this use case like a zillion times already: the caller manages her buffer, fun3() is allowed to change contents, but not reallocate caller's buffer. fun1() can't provide that (const), fun2() cannot either, because it explicitly allows reallocation (ref). This behavior is only provided by fun3(). So it's either that, or indeed cases of "I don't care about this array", which Maxim Fomin has mentioned.
Jan 30 2014
On Thursday, 30 January 2014 at 09:14:43 UTC, Cooler wrote:This is first problem. You are being explained what is the *purpose* of the fun3() but you repeatedly fail to accept it.If you want to modify the slice and make changes visible in caller, you should use ref. If you don't care whether changes are visible in caller, you can omit any attributes and use plain array. This belongs to the case you are asking about. If you don't want to change array in callee, pass it as const qualified. Now, after rethinking the issue I am inclining that "don't care whether changes are visible for caller" is not very wrong, but not very good design. Ideally it should be specified to avoid unexpected problems to pop up. So yes, it is better to qualify array. Another point. This casino games of whether changes would be visible or not is direct consequence of how slices are implemented (and how runtime service them). Remember, that many features in D work in a strange way not because of wise design but as a consequence of not fully thought design (like array). As a result, some features work in not best way they should. Although many folks in newsgroups would eagerly say that you don't understand the lang, it wouldn't make a bad design a good one.Please stop explain me how fun3() works. I know that.One of the main idea of D is that things must work as planned, or would not compile at all.Outcryingly wrong. Study bugzilla which shows how some things go wrong and read DIPs to learn that there are some issues in the language for which the communitty still struggles to formulate good solution.First and second variants follow this idea. But fun3() can work not as planned on the caller side (depends on fun3() body's implementation).Many things can work not as intended. Please read forums, bugzilla, etc. I bet passing array will not be the only thing you find confusing.The question again - may be prohibit fun3() variant?Prohibiting code like: void foo(int[] arr) {} would break hell of a code and pose doubts on what happens with arrays if so simple construction is prohibited. In addition, I mentioned that "don't care" is probably sometimes an option. Emitting warning here has some merits but it would be consitently ignored (I expect).
Jan 30 2014
No odds.Please stop explain me how fun3() works. I know that.This is first problem. You are being explained what is the *purpose* of the fun3() but you repeatedly fail to accept it.Now I am trying to speak ideally. What ideal language should be, not the practical implementation.One of the main idea of D is that things must work as planned, or would not compile at all.Outcryingly wrong. Study bugzilla which shows how some things go wrong and read DIPs to learn that there are some issues in the language for which the communitty still struggles to formulate good solution.Again - don't look back. Consider how we can make D better.First and second variants follow this idea. But fun3() can work not as planned on the caller side (depends on fun3() body's implementation).Many things can work not as intended. Please read forums, bugzilla, etc. I bet passing array will not be the only thing you find confusing.Again - stop consider current state of D implementation. Consider how we can make D better. I think fun3() push programmers to make errors.The question again - may be prohibit fun3() variant?Prohibiting code like: void foo(int[] arr) {} would break hell of a code and pose doubts on what happens with arrays if so simple construction is prohibited. In addition, I mentioned that "don't care" is probably sometimes an option. Emitting warning here has some merits but it would be consitently ignored (I expect).
Jan 30 2014
Cooler:Again - stop consider current state of D implementation. Consider how we can make D better. I think fun3() push programmers to make errors.I think functions like void fun(int[] a){} are bug prone, because you seem to change the length of the array inside the function, or if you perform an append you modify a new memory zone, but such changes are invisible from the caller. Some times this is what you want, and in some cases this is a programmer mistake (this bug happened to me several times). But I don't know what to change and if this situation can be improved now. Perhaps all that's left to improve is to add tests to a D lint that warns against this possible source of bugs. Bye, bearophile
Jan 30 2014
You wrote "this bug happened to me several times" :) This bug also happened with me :) I know that everybody uses variant of fun(int[] a){} everywhere. I understand that nobody will rewrite it source code. I just want to follow rule "Correct things must be simple. Wrong things must be difficult." As an example we can mark such usage as "deprecated", to push all programmers use more error prone variants.Again - stop consider current state of D implementation. Consider how we can make D better. I think fun3() push programmers to make errors.I think functions like void fun(int[] a){} are bug prone, because you seem to change the length of the array inside the function, or if you perform an append you modify a new memory zone, but such changes are invisible from the caller. Some times this is what you want, and in some cases this is a programmer mistake (this bug happened to me several times). But I don't know what to change and if this situation can be improved now. Perhaps all that's left to improve is to add tests to a D lint that warns against this possible source of bugs. Bye, bearophile
Jan 30 2014
On Thursday, 30 January 2014 at 10:49:42 UTC, Cooler wrote:Now I am trying to speak ideally. What ideal language should be, not the practical implementation....Again - don't look back. Consider how we can make D better....Again - stop consider current state of D implementation. Consider how we can make D better. I think fun3() push programmers to make errors.Looks like you are overestimating yourself. Now, try: 1) write pull request to reject the code 2) convince developers somehow that your proposal is good 3) convince Walter to accept the change 4) after merging pull convince angry maintainers that it is good idea to reject unqualified array passing because Cooler tries to make the language better
Jan 30 2014
On Thursday, 30 January 2014 at 11:06:03 UTC, Maxim Fomin wrote:On Thursday, 30 January 2014 at 10:49:42 UTC, Cooler wrote:Agree. As a first step I post this topic in the forum. If I found understanding I will follow all steps you mention :)Now I am trying to speak ideally. What ideal language should be, not the practical implementation....Again - don't look back. Consider how we can make D better....Again - stop consider current state of D implementation. Consider how we can make D better. I think fun3() push programmers to make errors.Looks like you are overestimating yourself. Now, try: 1) write pull request to reject the code 2) convince developers somehow that your proposal is good 3) convince Walter to accept the change 4) after merging pull convince angry maintainers that it is good idea to reject unqualified array passing because Cooler tries to make the language better
Jan 30 2014
On Wednesday, 29 January 2014 at 15:11:33 UTC, Cooler wrote:This behavior is just a consequence of the deliberate decision on how arrays should be implemented. Any decision would be a trade-off. Like, if you just disallow this signature, you will have to use .dup at the caller side if you want the semantics of fun3. And often this copy might be unnecessary. It's really like a ball under the carpet. You make it flat in one place, but the ball pops up in the other. The trade-off that D chooses is pretty reasonable. You just have to accept that and get used to it.Yes, that is how slices work in D. The following article explains the "non-determinism" that you mention: http://dlang.org/d-array-article.html AliThank you for the article. Quotation from the article "It is a good idea to note in the documentation how the passed in slice might or might not be overwritten." May be just prohibit at language level the case of fun3() function, to do not allow unpredictable behavior?
Jan 29 2014
This behavior is just a consequence of the deliberate decision on how arrays should be implemented. Any decision would be a trade-off. Like, if you just disallow this signature, you will have to use .dup at the caller side if you want the semantics of fun3. And often this copy might be unnecessary. It's really like a ball under the carpet. You make it flat in one place, but the ball pops up in the other. The trade-off that D chooses is pretty reasonable. You just have to accept that and get used to it.Ok! I agree with you! Can you just answer me http://forum.dlang.org/post/dxqxlhyhmdfuashhmtrz forum.dlang.org
Jan 29 2014
kOn Wed, 29 Jan 2014 05:55:56 -0500, Cooler <kulkin hotbox.ru> wrote:Consider 3 functions taking array as an argument: void fun1(in int[] x){...} void fun2(ref int[] x){...} void fun3( int[] x){...} auto a = new int[10]; fun1(a); // Guaranteed that "a" will not be changed fun2(a); // Guaranteed that we will see any change to "a", made in fun2() fun3(a); // Changes to "a" in fun3() may be or may be not visible to the caller In case of fun3() we have ambiguous behaviour, depending on the body of the function. Am I right?Yes.Is that intentional?Yes. I read the rest of the discussion. Arrays are hard to understand in D, especially if you have preconceived notions from other languages. But I would point out that fun2 does not "guarantee" anything more than fun3: void fun2(ref int [] x) { fun3(x); } It is an intrinsic property of slices that they do not own the data pointed at. You cannot guarantee that one slice's changes will affect another slice, AS LONG AS one slice is increasing its length. If you avoid increasing the length, then the results are deterministic. As I said in the article, avoid increasing the length, and THEN changing the original data. If you do that, you should have quite predictable results. If your code must do otherwise, explain in the documentation what should happen (i.e. don't use the passed-in slice after the function), and use some of the tricks to avoid it (use ref, or return the new slice data). -Steve
Jan 30 2014
On Thursday, 30 January 2014 at 13:44:39 UTC, Steven Schveighoffer wrote:kOn Wed, 29 Jan 2014 05:55:56 -0500, Cooler <kulkin hotbox.ru> wrote:If I don't want that fun() will change my array, i have to use fun1() variant. If I want fun() will change my array, i have to use fun2() variant. What fun2() do with it's argument inside it's body - not my business.Consider 3 functions taking array as an argument: void fun1(in int[] x){...} void fun2(ref int[] x){...} void fun3( int[] x){...} auto a = new int[10]; fun1(a); // Guaranteed that "a" will not be changed fun2(a); // Guaranteed that we will see any change to "a", made in fun2() fun3(a); // Changes to "a" in fun3() may be or may be not visible to the caller In case of fun3() we have ambiguous behaviour, depending on the body of the function. Am I right?Yes.Is that intentional?Yes. I read the rest of the discussion. Arrays are hard to understand in D, especially if you have preconceived notions from other languages. But I would point out that fun2 does not "guarantee" anything more than fun3: void fun2(ref int [] x) { fun3(x); }It is an intrinsic property of slices that they do not own the data pointed at. You cannot guarantee that one slice's changes will affect another slice, AS LONG AS one slice is increasing its length. If you avoid increasing the length, then the results are deterministic. As I said in the article, avoid increasing the length, and THEN changing the original data. If you do that, you should have quite predictable results. If your code must do otherwise, explain in the documentation what should happen (i.e. don't use the passed-in slice after the function), and use some of the tricks to avoid it (use ref, or return the new slice data). -Steve1. For example somebody already implemented fun1() and fun2() variants, as in my first post. This variants understandable and predictable. What can push me to ask another person for fun3() implementation, while it result is unpredictable, until you know fun3() body? 2. You wrote "If your code must do otherwise, explain in the documentation what should happen". That exactly what I am trying to discuss here. Instead of writing some documentation, just warn (and may be prohibit in far-far future) about such possible unpredictability during compilation.
Jan 30 2014
Forgot to mention :)"But I would point out that fun2 does not guarantee anything more than fun3:" - fun2() cannot guarantee anything because it calls fun3() which in turn cannot guarantee anything.I read the rest of the discussion. Arrays are hard to understand in D, especially if you have preconceived notions from other languages. But I would point out that fun2 does not "guarantee" anything more than fun3: void fun2(ref int [] x) { fun3(x); }
Jan 30 2014
On Thursday, 30 January 2014 at 14:18:41 UTC, Cooler wrote:"But I would point out that fun2 does not guarantee anything more than fun3:" - fun2() cannot guarantee anything because it calls fun3() which in turn cannot guarantee anything.Unrelated. void foo2(ref int[] arr) { /* do nothing */ } You can't guarantee mutation by function signature. Well, unless compiler does full attribute and qualifier inference.
Jan 30 2014
On Thu, 30 Jan 2014 09:18:40 -0500, Cooler <kulkin hotbox.ru> wrote:Forgot to mention :)Right, but you said this:"But I would point out that fun2 does not guarantee anything more than fun3:" - fun2() cannot guarantee anything because it calls fun3() which in turn cannot guarantee anything.I read the rest of the discussion. Arrays are hard to understand in D, especially if you have preconceived notions from other languages. But I would point out that fun2 does not "guarantee" anything more than fun3: void fun2(ref int [] x) { fun3(x); }fun2(a); // Guaranteed that we will see any change to "a", made in fun2()Which is false. That was my point. -Steve
Jan 30 2014
On Thu, 30 Jan 2014 09:07:14 -0500, Cooler <kulkin hotbox.ru> wrote:If I don't want that fun() will change my array, i have to use fun1() variant. If I want fun() will change my array, i have to use fun2() variant. What fun2() do with it's argument inside it's body - not my business.No. You can use fun3 variant as well: void fun3(int[] x) { x[] = 0; // guaranteed to be seen by caller. }1. For example somebody already implemented fun1() and fun2() variants, as in my first post. This variants understandable and predictable. What can push me to ask another person for fun3() implementation, while it result is unpredictable, until you know fun3() body?The only reason to have both fun2 and fun3 variants is if you want to handle both l-value and r-value options differently. There would be very few use cases which make sense AND return void. You usually want one or the other.2. You wrote "If your code must do otherwise, explain in the documentation what should happen". That exactly what I am trying to discuss here. Instead of writing some documentation, just warn (and may be prohibit in far-far future) about such possible unpredictability during compilation.No, because you are not understanding the effect of the attributes, and who is responsible for what. 1. Banning such signatures does NOT accomplish what you want. 2. Such signatures do NOT guarantee what happens inside the function. Having the compiler ban the problem where you expect the caller to see your changes, but they don't, is akin to just making the compiler able to detect all logic bugs. It's not possible (NP complete). The compiler just doesn't know what you really want to do. -Steve
Jan 30 2014
On Wednesday, 29 January 2014 at 10:55:57 UTC, Cooler wrote:Consider 3 functions taking array as an argument: void fun1(in int[] x){...} void fun2(ref int[] x){...} void fun3( int[] x){...} auto a = new int[10]; fun1(a); // Guaranteed that "a" will not be changed fun2(a); // Guaranteed that we will see any change to "a", made in fun2() fun3(a); // Changes to "a" in fun3() may be or may be not visible to the caller In case of fun3() we have ambiguous behaviour, depending on the body of the function. Am I right? Is that intentional?I believe what you are asking for is "head const." D does not do this, search for "head const dlang" and you'll probably find some discussion in it.
Jan 30 2014