www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Array slice assign syntax

reply bearophile <bearophileHUGS lycos.com> writes:
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
next sibling parent Manu <turkeyman gmail.com> writes:
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
prev sibling next sibling parent "Marco Leise" <Marco.Leise gmx.de> writes:
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
prev sibling next sibling parent =?utf-8?Q?Simen_Kj=C3=A6r=C3=A5s?= <simen.kjaras gmail.com> writes:
On Wed, 16 Nov 2011 04:24:25 +0100, bearophile <bearophileHUGS lycos.com>  
wrote:

[Good stuff]

Votes++
Nov 16 2011
prev sibling next sibling parent "Regan Heath" <regan netmail.co.nz> writes:
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
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
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.
Nov 16 2011
parent reply "Martin Nowak" <dawg dawgfoto.de> writes:
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:
 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
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.
 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 17 2011
parent Timon Gehr <timon.gehr gmx.ch> writes:
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:

 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
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.
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!
 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 17 2011