Array slice assign syntax

Timon Gehr timon.gehr at gmx.ch
Wed Nov 16 10:47:47 PST 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,
> bearophile

First 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.









More information about the Digitalmars-d mailing list