Array slice assign syntax
Martin Nowak
dawg at dawgfoto.de
Thu Nov 17 00:12:19 PST 2011
On Wed, 16 Nov 2011 19:47:47 +0100, Timon Gehr <timon.gehr at 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.
>
>
>
>
>
>
More information about the Digitalmars-d
mailing list