Array slice assign syntax

Timon Gehr timon.gehr at gmx.ch
Thu Nov 17 06:56:43 PST 2011


On 11/17/2011 09:12 AM, Martin Nowak wrote:
> 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.
>

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



More information about the Digitalmars-d mailing list