Request: a more logical static array behavior

Maxim Fomin maxim at maxim-fomin.ru
Thu Aug 15 00:16:00 PDT 2013


On Thursday, 15 August 2013 at 00:57:26 UTC, Tommi wrote:
>
> Static array types are somewhat magical in D; they can do 
> something that no other non-subtype type can do: static arrays 
> can implicitly convert to another type during type deduction. 
> More specifically, e.g. int[3] can implicitly convert to int[] 
> during type deduction.

I don't understand why are you surprising that int[3] can be 
implicitly converted to int[] during type deduction. There is 
nothing special about it since it can be converted in other 
contexts too.

> Here's an example of this:
>
> module test;
>
> enum Ret { static_array, dynamic_array, input_range }
>
> Ret foo(T)(T[3] sa) // [1]
> if (is(T == uint))
> {
>     return Ret.static_array;
> }
>
> Ret foo(T)(T[] da) // [2]
> {
>     return Ret.dynamic_array;
> }
>
> enum uint[3] saUints = [0, 0, 0];
> enum char[3] saChars = [0, 0, 0];
> static assert(foo(saUints) == Ret.static_array);  // [3]
> static assert(foo(saChars) == Ret.dynamic_array); // [4]
>
> -------
> [3]: A perfect match is found in the first overload of 'foo' 
> [1] when its template type parameter 'T' is deduced to be an 
> int. Then, the type of the function parameter 'sa' is exactly 
> the same as the type of the argument 'saUints'.
>
> [4]: No perfect match is found. But, because 'saChars' is a 
> static array, the compiler gives all 'foo' overloads the 
> benefit of the doubt, and also checks if a perfect match could 
> be found if 'saChars' were first converted to a dynamic array, 
> int[] that is. Then, a perfect match is found for int[] in the 
> second overload of 'foo' [2] when 'T' is deduced to be an int.

Compiler is integral entity. There is no providing "benefits to 
doubt". What actually happens is checking in 
TypeSArray::deduceType that base type of T[N] is base type of 
T[]. This check gives true since type 'int' is equal to 'int'. 
And resulted match is not a perfect match, but conversion match. 
Also actual conversion happens later in some completely unrelated 
to type deduction compiler part.

> Now, let's add to the previous example:
>
> import std.range;
>
> Ret bar(T)(T[3] sa) // [5]
> if (is(T == uint))
> {
>     return Ret.static_array;
> }
>
> Ret bar(R)(R r) // [6]
> if (std.range.isInputRange!R)
> {
>     return Ret.input_range;
> }
>
> static assert(bar(saUints) == Ret.static_array); // [7]
> static assert(bar(saChars) == Ret.input_range);  // [8]
>
> -------
> [7]: This is effectively the same as [3]
> [8]: This line throws a compile-time error: "template test.bar 
> does not match any function template declaration". Compare this 
> to [4]: for some reason, the compiler doesn't give the second 
> overload of 'bar' [6] the benefit of the doubt and check to see 
> if the call to 'bar' could be made if 'saChars' were first 
> converted to int[]. Were the compiler to consider this implicit 
> conversion as it does in [4], then it would see that the second 
> overload of 'bar' [6] could in fact be called, and the code 
> would compile.

Compiler "doesn't give the benefit to doubt" as there are no 
hints here about dynamic array. Taking into account general case, 
when A -> B and B ->C you are asking A ->C. And if B and C can 
convert to other types as well, than you could end up with 
exponentially increasing trees of what R may be or in situations 
where int[3] is converted to some ranged struct S { void 
popFront(){ } ... }

In other way, int[3] cannot be directly converted to R if int[3] 
-> int[] and int[] -> R holds. Also,as Jonathan said, there is 
safety aspect of this issue.

> Thus, my point is this:
> Shouldn't this magical property of static arrays (implicitly 
> converting to dynamic array during type deduction) extend to 
> all type deduction situations?

I guess you mean making two steps conversion. I think it is a bad 
idea.




More information about the Digitalmars-d mailing list