Comment #0 by dlang-bugzilla — 2012-02-13T06:26:16Z
void main()
{
string str = "Hi";
void[][1] arr = [str];
assert(arr[0].length == str.length);
}
Notably, changing the second line to
void[][1] arr = str;
will make the assert pass, so I guess DMD is now trying some new way of array assignment which succeeds due to the implicit void[] conversion.
Worked in 1.070, doesn't work in 1.071 or the latest D1 beta.
Comment #1 by bugzilla — 2012-02-14T00:48:11Z
Since it's not a regression in 1.072, I'm going to defer this until the next cycle.
Comment #2 by clugdbug — 2012-03-19T22:24:25Z
Also applies to D2. The problem is that there are two possible interpretations:
void[] x = [str];
typeof(x)[1] = x;
void[] y = str;
typeof(y)[1] = [ y ];
I think this should be an error.
Comment #3 by clugdbug — 2012-03-20T14:18:58Z
This change was caused by the fix to bug 3069,
which allows any array to implicitly cast to void[].
In this case it converts from string[] to void[]. The assert which passes is:
assert(arr[0].length == (cast(void[])[str]).length);
The rule seems to be, that an when initializing an array with an array literal, if the value can be interpreted as an element-wise assignment, it will be.
Otherwise, it will be interpreted as a full assignment.
Still, there is something a bit odd.
import std.stdio;
void main()
{
void [][3] y = [[],[],[]];
void [][] z = [[],[],[]];
writefln("y: %d %d z: %d %d", y.length, y[0].length, z.length, z[0].length);
}
y: 3 48 z: 3 0
Comment #4 by timon.gehr — 2012-03-21T13:10:05Z
DMD is inconsistent here. It is not clear what the behavior should be.
void main(){
string[] s1,s2;
s1=s1~[];
s2~=[];
writeln(s1," ",s2); // [""] []
}
I think most reasonable would be to check the array type for implicit conversions first and to consider the element type for implicit conversions only after the conversion to the array has failed. This would make appending/concatenating with an empty array literal a no-op for all array types and it would restore the behavior the OP expects.
Comment #5 by clugdbug — 2012-03-21T14:14:57Z
(In reply to comment #4)
> DMD is inconsistent here. It is not clear what the behavior should be.
>
> void main(){
> string[] s1,s2;
> s1=s1~[];
> s2~=[];
> writeln(s1," ",s2); // [""] []
> }
>
> I think most reasonable would be to check the array type for implicit
> conversions first and to consider the element type for implicit conversions
> only after the conversion to the array has failed.
I don't think that's the same issue, and I don't like that approach for initialization of void[]. It would mean that
void[][3] a = [ str, str, str];
void[][2] b = [ str, str, str];
means
a[0] == str
b[0] == [str, str, str]
I think this particular issue is specific to void[], since it is a recursive type (an array literal of void[] elements is also of type void[]).
The most intuitive approaches I would think are:
* void[][ANYTHING] = [ WHATEVER ] is _always_ a whole-array assignment;
OR
it is _always_ an error.
The current compiler behaviour, where it is always a block assignment, is less intuitive but I think defensible.
But allowing it to be one or the other, depending on whether the implicit conversion succeeds, is horribly unpredictable.
As far as I can tell, there is no mention at all of block assignment in the spec! Did I miss it?
> This would make
> appending/concatenating with an empty array literal a no-op for all array types
> and it would restore the behavior the OP expects.
Comment #6 by timon.gehr — 2012-03-21T15:13:28Z
(In reply to comment #5)
> (In reply to comment #4)
> > DMD is inconsistent here. It is not clear what the behavior should be.
> >
> > void main(){
> > string[] s1,s2;
> > s1=s1~[];
> > s2~=[];
> > writeln(s1," ",s2); // [""] []
> > }
> >
> > I think most reasonable would be to check the array type for implicit
> > conversions first and to consider the element type for implicit conversions
> > only after the conversion to the array has failed.
>
> I don't think that's the same issue,
It is very closely related. It is the same kind of issue.
> and I don't like that approach for
> initialization of void[]. It would mean that
> void[][3] a = [ str, str, str];
> void[][2] b = [ str, str, str];
>
> means
>
> a[0] == str
> b[0] == [str, str, str]
I see. That is a problem.
>
> I think this particular issue is specific to void[], since it is a recursive
> type (an array literal of void[] elements is also of type void[]).
>
The particular issue is specific to void[]. Possible resolutions could affect the entire language. (for example, this issue came up because of an only roughly related fix)
> The most intuitive approaches I would think are:
> * void[][ANYTHING] = [ WHATEVER ] is _always_ a whole-array assignment;
I think that is the best behavior. Block assignment can still work with []= .
> OR
> it is _always_ an error.
Then how do you initialize it? Element-wise?
> The current compiler behaviour, where it is always a block assignment, is less
> intuitive but I think defensible.
> But allowing it to be one or the other, depending on whether the implicit
> conversion succeeds, is horribly unpredictable.
>
> As far as I can tell, there is no mention at all of block assignment in the
> spec! Did I miss it?
>
The conversion rules for arrays and array literals are almost completely unspecified afaik.
Another ambiguous case:
import std.stdio;
class A{
A[] as;
this(){as = [new A(0),new A(0)];}
this(int){}
alias as this;
}
void main(){
A a = new A;
A[] as1;
A[] as2;
as1=as1~a;
as2~=a;
writeln(as1.length," ",as2.length); // 2 2
}