digitalmars.D - Array slice assign syntax
- bearophile (110/110) Nov 15 2011 The Bugzilla issues that I really care about is a not an useless long li...
- Manu (6/129) Nov 16 2011 This makes perfect sense to me as a new-comer, and having not had much
- Marco Leise (4/4) Nov 16 2011 a = b for two static arrays of the same type and size is ok for me,
-
=?utf-8?Q?Simen_Kj=C3=A6r=C3=A5s?=
(4/4)
Nov 16 2011
On Wed, 16 Nov 2011 04:24:25 +0100, bearophile
-
Regan Heath
(10/13)
Nov 16 2011
On Wed, 16 Nov 2011 03:24:25 -0000, bearophile
- Timon Gehr (72/182) Nov 16 2011 First thing:
- Martin Nowak (5/256) Nov 17 2011 No there are not, a owns no storage to hold values, it is only a slice.
- Timon Gehr (11/309) Nov 17 2011 My goal was to deduce consistent rules. Those are the only two options
The Bugzilla issues that I really care about is a not an useless long list, it's about fifteen items long, and this post is about one of them. I think current array slice assign syntax is a bit messy, and I think this should be addressed. Kenji Hara has recently written a very nice program (that here I have modified a bit for clarity) that shows the current array assign situation: import std.stdio, std.typetuple; void main() { writeln("Rhs is an array, is it compilable?"); writeln("a\t/ b\t\ta=b\ta[]=b\ta=b[]\ta[]=b[]"); foreach (i, Lhs; TypeTuple!(int[3], int[])) foreach (j, Rhs; TypeTuple!(int[3], int[])) { writef("%s\t/ %s ", Lhs.stringof, Rhs.stringof); Lhs a = [0,0,0]; Rhs b = [1,2,3]; writef("\t%s", __traits(compiles, { a = b; })); writef("\t%s", __traits(compiles, { a[] = b; })); writef("\t%s", __traits(compiles, { a = b[]; })); writef("\t%s", __traits(compiles, { a[] = b[]; })); writeln(); } writeln("\nRhs is a element, is it compilable?"); writeln("a\t\t\ta=N\ta[]=N\ta[0..2]=N"); foreach (Lhs; TypeTuple!(int[3], int[])) { writef("%s\t\t", Lhs.stringof); Lhs a = [0,0,0]; writef("\t%s", __traits(compiles, { a = 9; })); writef("\t%s", __traits(compiles, { a[] = 9; })); writef("\t%s", __traits(compiles, { a[0..2] = 9; })); writeln(); } } Currently (DMD 2.057head, despite I think Walter has not updated DMD version number yet) it prints: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] true true true true int[3u] / int[] true true true true int[] / int[3u] true true true true int[] / int[] true true true true Rhs is a element, is it compilable? a a=N a[]=N a[0..2]=N int[3u] true true true int[] false true true This also means this is currently accepted: void main() { int[3] a; a = 1; assert(a == [1, 1, 1]); } While this is not accepted: void main() { int[] b = new int[3]; b = 1; assert(b == [1, 1, 1]); //Error: cannot implicitly convert expression (1) of type int to int[] } I'd like D to require a[]=1 in that first case too. I'd like the [] to be required every time an O(n) vector operation is done, for: - constancy with all other vector operations among two arrays, that require []; - and to avoid unwanted (and not easy to spot in the code) O(n) operations; - bugs and confusion in D newbies that don't have memorized all current special cases. On the other hand Don says that [] is only required for lvalues. I think this boils to a new table like this: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] FALSE true FALSE true int[3u] / int[] FALSE true FALSE true int[] / int[3u] FALSE true FALSE true int[] / int[] true true true true Rhs is a element, is it compilable? a a=N a[]=N a[0..2]=N int[3u] FALSE true true int[] false true true Now if there's a [] on the left, then it's an O(n) vector operation (like a copy), otherwise it's O(1). That also means: void main() { int[] a = new int[3]; int[] b = new int[3]; a = b; // OK, copies just array fat reference } void main() { int[3] a, b; a = b; // Not OK, hidden vector op } I am not sure this new table is fully correct, but it's a start. Fixes of mistakes are welcomes. ----------------------- This is an alternative proposal. On the other hand this vector op syntax doesn't currently compile: void main() { int[3] a, b; a[] += b; } So if array assign is seen as a normal vector op, then the [] is needed on the right too: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] FALSE FALSE FALSE true int[3u] / int[] FALSE FALSE FALSE true int[] / int[3u] FALSE FALSE FALSE true int[] / int[] true FALSE FALSE true Rhs is a element, is it compilable? a a=N a[]=N a[0..2]=N int[3u] FALSE true true int[] false true true Where the two cases with dynamic arrays are syntax errors to keep more symmetry: void main() { int[] a = new int[3]; int[] b = new int[3]; a[] = b; // error a = b[]; // error } ----------------------- Lot of time ago I have opened bug issue 3971 on this topic, but that Bugzilla thread contains various mistakes and some parts of it are obsolete. Bye, bearophile
Nov 15 2011
This makes perfect sense to me as a new-comer, and having not had much experience writing this sort of code, this is exactly how I would have assumed it is now. I would have been in for a confusing surprise had I tried to do any of this stuff. On 16 November 2011 05:24, bearophile <bearophileHUGS lycos.com> wrote:The Bugzilla issues that I really care about is a not an useless long list, it's about fifteen items long, and this post is about one of them. I think current array slice assign syntax is a bit messy, and I think this should be addressed. Kenji Hara has recently written a very nice program (that here I have modified a bit for clarity) that shows the current array assign situation: import std.stdio, std.typetuple; void main() { writeln("Rhs is an array, is it compilable?"); writeln("a\t/ b\t\ta=b\ta[]=b\ta=b[]\ta[]=b[]"); foreach (i, Lhs; TypeTuple!(int[3], int[])) foreach (j, Rhs; TypeTuple!(int[3], int[])) { writef("%s\t/ %s ", Lhs.stringof, Rhs.stringof); Lhs a = [0,0,0]; Rhs b = [1,2,3]; writef("\t%s", __traits(compiles, { a = b; })); writef("\t%s", __traits(compiles, { a[] = b; })); writef("\t%s", __traits(compiles, { a = b[]; })); writef("\t%s", __traits(compiles, { a[] = b[]; })); writeln(); } writeln("\nRhs is a element, is it compilable?"); writeln("a\t\t\ta=N\ta[]=N\ta[0..2]=N"); foreach (Lhs; TypeTuple!(int[3], int[])) { writef("%s\t\t", Lhs.stringof); Lhs a = [0,0,0]; writef("\t%s", __traits(compiles, { a = 9; })); writef("\t%s", __traits(compiles, { a[] = 9; })); writef("\t%s", __traits(compiles, { a[0..2] = 9; })); writeln(); } } Currently (DMD 2.057head, despite I think Walter has not updated DMD version number yet) it prints: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] true true true true int[3u] / int[] true true true true int[] / int[3u] true true true true int[] / int[] true true true true Rhs is a element, is it compilable? a a=N a[]=N a[0..2]=N int[3u] true true true int[] false true true This also means this is currently accepted: void main() { int[3] a; a = 1; assert(a == [1, 1, 1]); } While this is not accepted: void main() { int[] b = new int[3]; b = 1; assert(b == [1, 1, 1]); //Error: cannot implicitly convert expression (1) of type int to int[] } I'd like D to require a[]=1 in that first case too. I'd like the [] to be required every time an O(n) vector operation is done, for: - constancy with all other vector operations among two arrays, that require []; - and to avoid unwanted (and not easy to spot in the code) O(n) operations; - bugs and confusion in D newbies that don't have memorized all current special cases. On the other hand Don says that [] is only required for lvalues. I think this boils to a new table like this: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] FALSE true FALSE true int[3u] / int[] FALSE true FALSE true int[] / int[3u] FALSE true FALSE true int[] / int[] true true true true Rhs is a element, is it compilable? a a=N a[]=N a[0..2]=N int[3u] FALSE true true int[] false true true Now if there's a [] on the left, then it's an O(n) vector operation (like a copy), otherwise it's O(1). That also means: void main() { int[] a = new int[3]; int[] b = new int[3]; a = b; // OK, copies just array fat reference } void main() { int[3] a, b; a = b; // Not OK, hidden vector op } I am not sure this new table is fully correct, but it's a start. Fixes of mistakes are welcomes. ----------------------- This is an alternative proposal. On the other hand this vector op syntax doesn't currently compile: void main() { int[3] a, b; a[] += b; } So if array assign is seen as a normal vector op, then the [] is needed on the right too: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] FALSE FALSE FALSE true int[3u] / int[] FALSE FALSE FALSE true int[] / int[3u] FALSE FALSE FALSE true int[] / int[] true FALSE FALSE true Rhs is a element, is it compilable? a a=N a[]=N a[0..2]=N int[3u] FALSE true true int[] false true true Where the two cases with dynamic arrays are syntax errors to keep more symmetry: void main() { int[] a = new int[3]; int[] b = new int[3]; a[] = b; // error a = b[]; // error } ----------------------- Lot of time ago I have opened bug issue 3971 on this topic, but that Bugzilla thread contains various mistakes and some parts of it are obsolete. Bye, bearophile
Nov 16 2011
a = b for two static arrays of the same type and size is ok for me, especially when the size is small. I get your point though and like a strict syntax, too. The notion of a vector operation always using [] seems natural.
Nov 16 2011
On Wed, 16 Nov 2011 04:24:25 +0100, bearophile <bearophileHUGS lycos.com> wrote: [Good stuff] Votes++
Nov 16 2011
On Wed, 16 Nov 2011 03:24:25 -0000, bearophile <bearophileHUGS lycos.com> wrote: +1 vote toward looking into this more. I like the idea of a more consistent syntax, and the [] requirement for vector operations vs single/simple assignment.Lot of time ago I have opened bug issue 3971 on this topic, but that Bugzilla thread contains various mistakes and some parts of it are obsolete.So.. create a new BZ, put the content of your message here in it, and mark the old one a duplicate of the new one .. or mark the old one invalid, and simply create a new one with this content. -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Nov 16 2011
On 11/16/2011 04:24 AM, bearophile wrote:The Bugzilla issues that I really care about is a not an useless long list, it's about fifteen items long, and this post is about one of them. I think current array slice assign syntax is a bit messy, and I think this should be addressed. Kenji Hara has recently written a very nice program (that here I have modified a bit for clarity) that shows the current array assign situation: import std.stdio, std.typetuple; void main() { writeln("Rhs is an array, is it compilable?"); writeln("a\t/ b\t\ta=b\ta[]=b\ta=b[]\ta[]=b[]"); foreach (i, Lhs; TypeTuple!(int[3], int[])) foreach (j, Rhs; TypeTuple!(int[3], int[])) { writef("%s\t/ %s ", Lhs.stringof, Rhs.stringof); Lhs a = [0,0,0]; Rhs b = [1,2,3]; writef("\t%s", __traits(compiles, { a = b; })); writef("\t%s", __traits(compiles, { a[] = b; })); writef("\t%s", __traits(compiles, { a = b[]; })); writef("\t%s", __traits(compiles, { a[] = b[]; })); writeln(); } writeln("\nRhs is a element, is it compilable?"); writeln("a\t\t\ta=N\ta[]=N\ta[0..2]=N"); foreach (Lhs; TypeTuple!(int[3], int[])) { writef("%s\t\t", Lhs.stringof); Lhs a = [0,0,0]; writef("\t%s", __traits(compiles, { a = 9; })); writef("\t%s", __traits(compiles, { a[] = 9; })); writef("\t%s", __traits(compiles, { a[0..2] = 9; })); writeln(); } } Currently (DMD 2.057head, despite I think Walter has not updated DMD version number yet) it prints: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] true true true true int[3u] / int[] true true true true int[] / int[3u] true true true true int[] / int[] true true true true Rhs is a element, is it compilable? a a=N a[]=N a[0..2]=N int[3u] true true true int[] false true true This also means this is currently accepted: void main() { int[3] a; a = 1; assert(a == [1, 1, 1]); } While this is not accepted: void main() { int[] b = new int[3]; b = 1; assert(b == [1, 1, 1]); //Error: cannot implicitly convert expression (1) of type int to int[] } I'd like D to require a[]=1 in that first case too. I'd like the [] to be required every time an O(n) vector operation is done, for: - constancy with all other vector operations among two arrays, that require []; - and to avoid unwanted (and not easy to spot in the code) O(n) operations; - bugs and confusion in D newbies that don't have memorized all current special cases. On the other hand Don says that [] is only required for lvalues. I think this boils to a new table like this: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] FALSE true FALSE true int[3u] / int[] FALSE true FALSE true int[] / int[3u] FALSE true FALSE true int[] / int[] true true true true Rhs is a element, is it compilable? a a=N a[]=N a[0..2]=N int[3u] FALSE true true int[] false true true Now if there's a [] on the left, then it's an O(n) vector operation (like a copy), otherwise it's O(1). That also means: void main() { int[] a = new int[3]; int[] b = new int[3]; a = b; // OK, copies just array fat reference } void main() { int[3] a, b; a = b; // Not OK, hidden vector op } I am not sure this new table is fully correct, but it's a start. Fixes of mistakes are welcomes. ----------------------- This is an alternative proposal. On the other hand this vector op syntax doesn't currently compile: void main() { int[3] a, b; a[] += b; } So if array assign is seen as a normal vector op, then the [] is needed on the right too: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] FALSE FALSE FALSE true int[3u] / int[] FALSE FALSE FALSE true int[] / int[3u] FALSE FALSE FALSE true int[] / int[] true FALSE FALSE true Rhs is a element, is it compilable? a a=N a[]=N a[0..2]=N int[3u] FALSE true true int[] false true true Where the two cases with dynamic arrays are syntax errors to keep more symmetry: void main() { int[] a = new int[3]; int[] b = new int[3]; a[] = b; // error a = b[]; // error } ----------------------- Lot of time ago I have opened bug issue 3971 on this topic, but that Bugzilla thread contains various mistakes and some parts of it are obsolete. Bye, bearophileFirst thing: int[3] a=3; // kill it!! Rest: a[] is _just a shortcut_ for a[0..$]! Are you really suggesting to disallow slicing? You are thinking too much in terms of syntax and not enough in terms of semantics. They are basically two distinct things involved here: 1. static arrays and lvalue slices 2. dynamic arrays and rvalue slices 1 implies value semantics, 2 implies reference semantics, where value semantics overrides reference semantics. Any other distinction is more or less arbitrary. As you pointed out, the main indicator of distinction is value vs reference semantics of the performed assignments. We certainly agree on this: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] ? ? ? true int[3u] / int[] ? ? ? true int[] / int[3u] ? ? ? true int[] / int[] ? ? ? true Now, a dynamic array a is equivalent to a[], and a static array b is equivalent to an lvalue slice b[]=. This gives the following equivalence classes of operations: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] 1 1 2 2 int[3u] / int[] 2 2 2 2 int[] / int[3u] 3 1 4 2 int[] / int[] 4 2 4 2 Any of the same class should behave the same. Now, you suggest in both proposals to allow at least one of class 2 and at least one of class 4. Filling all those out delivers: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] (1) (1) true true int[3u] / int[] true true true true int[] / int[3u] (3) (1) true true int[] / int[] true true true true 1 is "assign value to value". 3. is "assign value to reference". The upper left corner should certainly be true, values of any mutable type should be able to be assigned to themselves. This leaves: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] true true true true int[3u] / int[] true true true true int[] / int[3u] (3) true true true int[] / int[] true true true true 3 is the odd thing out. Now let's think about it, what should: int[] a; int[3] b; a=b; do? The answer is, there are two options. 1. implicitly slice b 2. copy b by value into a One is as arbitrary as the other, so it should be disallowed in a sane design. Which leaves: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] true true true true int[3u] / int[] true true true true int[] / int[3u] FALSE true true true int[] / int[] true true true true Rhs is a element, is it compilable? a a=N a[]=N a[0..2]=N int[3u] FALSE true true int[] false true true And that is how it should be.
Nov 16 2011
On Wed, 16 Nov 2011 19:47:47 +0100, Timon Gehr <timon.gehr gmx.ch> wrote:On 11/16/2011 04:24 AM, bearophile wrote:No there are not, a owns no storage to hold values, it is only a slice. In that case a should be be a slice of the static array b. It could make sense to require b[] for the conversion, but copying is no option.The Bugzilla issues that I really care about is a not an useless long list, it's about fifteen items long, and this post is about one of them. I think current array slice assign syntax is a bit messy, and I think this should be addressed. Kenji Hara has recently written a very nice program (that here I have modified a bit for clarity) that shows the current array assign situation: import std.stdio, std.typetuple; void main() { writeln("Rhs is an array, is it compilable?"); writeln("a\t/ b\t\ta=b\ta[]=b\ta=b[]\ta[]=b[]"); foreach (i, Lhs; TypeTuple!(int[3], int[])) foreach (j, Rhs; TypeTuple!(int[3], int[])) { writef("%s\t/ %s ", Lhs.stringof, Rhs.stringof); Lhs a = [0,0,0]; Rhs b = [1,2,3]; writef("\t%s", __traits(compiles, { a = b; })); writef("\t%s", __traits(compiles, { a[] = b; })); writef("\t%s", __traits(compiles, { a = b[]; })); writef("\t%s", __traits(compiles, { a[] = b[]; })); writeln(); } writeln("\nRhs is a element, is it compilable?"); writeln("a\t\t\ta=N\ta[]=N\ta[0..2]=N"); foreach (Lhs; TypeTuple!(int[3], int[])) { writef("%s\t\t", Lhs.stringof); Lhs a = [0,0,0]; writef("\t%s", __traits(compiles, { a = 9; })); writef("\t%s", __traits(compiles, { a[] = 9; })); writef("\t%s", __traits(compiles, { a[0..2] = 9; })); writeln(); } } Currently (DMD 2.057head, despite I think Walter has not updated DMD version number yet) it prints: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] true true true true int[3u] / int[] true true true true int[] / int[3u] true true true true int[] / int[] true true true true Rhs is a element, is it compilable? a a=N a[]=N a[0..2]=N int[3u] true true true int[] false true true This also means this is currently accepted: void main() { int[3] a; a = 1; assert(a == [1, 1, 1]); } While this is not accepted: void main() { int[] b = new int[3]; b = 1; assert(b == [1, 1, 1]); //Error: cannot implicitly convert expression (1) of type int to int[] } I'd like D to require a[]=1 in that first case too. I'd like the [] to be required every time an O(n) vector operation is done, for: - constancy with all other vector operations among two arrays, that require []; - and to avoid unwanted (and not easy to spot in the code) O(n) operations; - bugs and confusion in D newbies that don't have memorized all current special cases. On the other hand Don says that [] is only required for lvalues. I think this boils to a new table like this: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] FALSE true FALSE true int[3u] / int[] FALSE true FALSE true int[] / int[3u] FALSE true FALSE true int[] / int[] true true true true Rhs is a element, is it compilable? a a=N a[]=N a[0..2]=N int[3u] FALSE true true int[] false true true Now if there's a [] on the left, then it's an O(n) vector operation (like a copy), otherwise it's O(1). That also means: void main() { int[] a = new int[3]; int[] b = new int[3]; a = b; // OK, copies just array fat reference } void main() { int[3] a, b; a = b; // Not OK, hidden vector op } I am not sure this new table is fully correct, but it's a start. Fixes of mistakes are welcomes. ----------------------- This is an alternative proposal. On the other hand this vector op syntax doesn't currently compile: void main() { int[3] a, b; a[] += b; } So if array assign is seen as a normal vector op, then the [] is needed on the right too: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] FALSE FALSE FALSE true int[3u] / int[] FALSE FALSE FALSE true int[] / int[3u] FALSE FALSE FALSE true int[] / int[] true FALSE FALSE true Rhs is a element, is it compilable? a a=N a[]=N a[0..2]=N int[3u] FALSE true true int[] false true true Where the two cases with dynamic arrays are syntax errors to keep more symmetry: void main() { int[] a = new int[3]; int[] b = new int[3]; a[] = b; // error a = b[]; // error } ----------------------- Lot of time ago I have opened bug issue 3971 on this topic, but that Bugzilla thread contains various mistakes and some parts of it are obsolete. Bye, bearophileFirst thing: int[3] a=3; // kill it!! Rest: a[] is _just a shortcut_ for a[0..$]! Are you really suggesting to disallow slicing? You are thinking too much in terms of syntax and not enough in terms of semantics. They are basically two distinct things involved here: 1. static arrays and lvalue slices 2. dynamic arrays and rvalue slices 1 implies value semantics, 2 implies reference semantics, where value semantics overrides reference semantics. Any other distinction is more or less arbitrary. As you pointed out, the main indicator of distinction is value vs reference semantics of the performed assignments. We certainly agree on this: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] ? ? ? true int[3u] / int[] ? ? ? true int[] / int[3u] ? ? ? true int[] / int[] ? ? ? true Now, a dynamic array a is equivalent to a[], and a static array b is equivalent to an lvalue slice b[]=. This gives the following equivalence classes of operations: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] 1 1 2 2 int[3u] / int[] 2 2 2 2 int[] / int[3u] 3 1 4 2 int[] / int[] 4 2 4 2 Any of the same class should behave the same. Now, you suggest in both proposals to allow at least one of class 2 and at least one of class 4. Filling all those out delivers: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] (1) (1) true true int[3u] / int[] true true true true int[] / int[3u] (3) (1) true true int[] / int[] true true true true 1 is "assign value to value". 3. is "assign value to reference". The upper left corner should certainly be true, values of any mutable type should be able to be assigned to themselves. This leaves: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] true true true true int[3u] / int[] true true true true int[] / int[3u] (3) true true true int[] / int[] true true true true 3 is the odd thing out. Now let's think about it, what should: int[] a; int[3] b; a=b; do? The answer is, there are two options. 1. implicitly slice b 2. copy b by value into aOne is as arbitrary as the other, so it should be disallowed in a sane design. Which leaves: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] true true true true int[3u] / int[] true true true true int[] / int[3u] FALSE true true true int[] / int[] true true true true Rhs is a element, is it compilable? a a=N a[]=N a[0..2]=N int[3u] FALSE true true int[] false true true And that is how it should be.
Nov 17 2011
On 11/17/2011 09:12 AM, Martin Nowak wrote:On Wed, 16 Nov 2011 19:47:47 +0100, Timon Gehr <timon.gehr gmx.ch> wrote:My goal was to deduce consistent rules. Those are the only two options /for assignment behaviour of arrays/, and both are equally bad in this case: // this is your argument against value semantics: a = ...; // everywhere else this means reference assign // this is an argument against reference semantics: ... = b; // everywhere else this means copy by value // which leaves us with: a = b; // ???! So indeed, for the behaviour of a=b; none of them 'is an option'. I should probably have formulated that better. Thanks!On 11/16/2011 04:24 AM, bearophile wrote:No there are not, a owns no storage to hold values, it is only a slice. In that case a should be be a slice of the static array b. It could make sense to require b[] for the conversion, but copying is no option.The Bugzilla issues that I really care about is a not an useless long list, it's about fifteen items long, and this post is about one of them. I think current array slice assign syntax is a bit messy, and I think this should be addressed. Kenji Hara has recently written a very nice program (that here I have modified a bit for clarity) that shows the current array assign situation: import std.stdio, std.typetuple; void main() { writeln("Rhs is an array, is it compilable?"); writeln("a\t/ b\t\ta=b\ta[]=b\ta=b[]\ta[]=b[]"); foreach (i, Lhs; TypeTuple!(int[3], int[])) foreach (j, Rhs; TypeTuple!(int[3], int[])) { writef("%s\t/ %s ", Lhs.stringof, Rhs.stringof); Lhs a = [0,0,0]; Rhs b = [1,2,3]; writef("\t%s", __traits(compiles, { a = b; })); writef("\t%s", __traits(compiles, { a[] = b; })); writef("\t%s", __traits(compiles, { a = b[]; })); writef("\t%s", __traits(compiles, { a[] = b[]; })); writeln(); } writeln("\nRhs is a element, is it compilable?"); writeln("a\t\t\ta=N\ta[]=N\ta[0..2]=N"); foreach (Lhs; TypeTuple!(int[3], int[])) { writef("%s\t\t", Lhs.stringof); Lhs a = [0,0,0]; writef("\t%s", __traits(compiles, { a = 9; })); writef("\t%s", __traits(compiles, { a[] = 9; })); writef("\t%s", __traits(compiles, { a[0..2] = 9; })); writeln(); } } Currently (DMD 2.057head, despite I think Walter has not updated DMD version number yet) it prints: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] true true true true int[3u] / int[] true true true true int[] / int[3u] true true true true int[] / int[] true true true true Rhs is a element, is it compilable? a a=N a[]=N a[0..2]=N int[3u] true true true int[] false true true This also means this is currently accepted: void main() { int[3] a; a = 1; assert(a == [1, 1, 1]); } While this is not accepted: void main() { int[] b = new int[3]; b = 1; assert(b == [1, 1, 1]); //Error: cannot implicitly convert expression (1) of type int to int[] } I'd like D to require a[]=1 in that first case too. I'd like the [] to be required every time an O(n) vector operation is done, for: - constancy with all other vector operations among two arrays, that require []; - and to avoid unwanted (and not easy to spot in the code) O(n) operations; - bugs and confusion in D newbies that don't have memorized all current special cases. On the other hand Don says that [] is only required for lvalues. I think this boils to a new table like this: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] FALSE true FALSE true int[3u] / int[] FALSE true FALSE true int[] / int[3u] FALSE true FALSE true int[] / int[] true true true true Rhs is a element, is it compilable? a a=N a[]=N a[0..2]=N int[3u] FALSE true true int[] false true true Now if there's a [] on the left, then it's an O(n) vector operation (like a copy), otherwise it's O(1). That also means: void main() { int[] a = new int[3]; int[] b = new int[3]; a = b; // OK, copies just array fat reference } void main() { int[3] a, b; a = b; // Not OK, hidden vector op } I am not sure this new table is fully correct, but it's a start. Fixes of mistakes are welcomes. ----------------------- This is an alternative proposal. On the other hand this vector op syntax doesn't currently compile: void main() { int[3] a, b; a[] += b; } So if array assign is seen as a normal vector op, then the [] is needed on the right too: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] FALSE FALSE FALSE true int[3u] / int[] FALSE FALSE FALSE true int[] / int[3u] FALSE FALSE FALSE true int[] / int[] true FALSE FALSE true Rhs is a element, is it compilable? a a=N a[]=N a[0..2]=N int[3u] FALSE true true int[] false true true Where the two cases with dynamic arrays are syntax errors to keep more symmetry: void main() { int[] a = new int[3]; int[] b = new int[3]; a[] = b; // error a = b[]; // error } ----------------------- Lot of time ago I have opened bug issue 3971 on this topic, but that Bugzilla thread contains various mistakes and some parts of it are obsolete. Bye, bearophileFirst thing: int[3] a=3; // kill it!! Rest: a[] is _just a shortcut_ for a[0..$]! Are you really suggesting to disallow slicing? You are thinking too much in terms of syntax and not enough in terms of semantics. They are basically two distinct things involved here: 1. static arrays and lvalue slices 2. dynamic arrays and rvalue slices 1 implies value semantics, 2 implies reference semantics, where value semantics overrides reference semantics. Any other distinction is more or less arbitrary. As you pointed out, the main indicator of distinction is value vs reference semantics of the performed assignments. We certainly agree on this: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] ? ? ? true int[3u] / int[] ? ? ? true int[] / int[3u] ? ? ? true int[] / int[] ? ? ? true Now, a dynamic array a is equivalent to a[], and a static array b is equivalent to an lvalue slice b[]=. This gives the following equivalence classes of operations: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] 1 1 2 2 int[3u] / int[] 2 2 2 2 int[] / int[3u] 3 1 4 2 int[] / int[] 4 2 4 2 Any of the same class should behave the same. Now, you suggest in both proposals to allow at least one of class 2 and at least one of class 4. Filling all those out delivers: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] (1) (1) true true int[3u] / int[] true true true true int[] / int[3u] (3) (1) true true int[] / int[] true true true true 1 is "assign value to value". 3. is "assign value to reference". The upper left corner should certainly be true, values of any mutable type should be able to be assigned to themselves. This leaves: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] true true true true int[3u] / int[] true true true true int[] / int[3u] (3) true true true int[] / int[] true true true true 3 is the odd thing out. Now let's think about it, what should: int[] a; int[3] b; a=b; do? The answer is, there are two options. 1. implicitly slice b 2. copy b by value into aOne is as arbitrary as the other, so it should be disallowed in a sane design. Which leaves: Rhs is an array, is it compilable? a / b a=b a[]=b a=b[] a[]=b[] int[3u] / int[3u] true true true true int[3u] / int[] true true true true int[] / int[3u] FALSE true true true int[] / int[] true true true true Rhs is a element, is it compilable? a a=N a[]=N a[0..2]=N int[3u] FALSE true true int[] false true true And that is how it should be.
Nov 17 2011