Request: a more logical static array behavior

Tommi tommitissari at hotmail.com
Thu Aug 15 05:44:07 PDT 2013


On Thursday, 15 August 2013 at 07:16:01 UTC, Maxim Fomin wrote:
> 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.

I don't expect int[3] to implicitly convert to int[] during type 
deduction for the same reason that I don't expect int to 
implicitly convert to long during type deduction (even though I 
know that int implicitly converts to long in all kinds of other 
contexts):

void getLong(T)(T arg)
if (is(T == long))
{
}

void main()
{
     int n;
     getLong(n); // int doesn't implicitly convert to long
}

On Thursday, 15 August 2013 at 07:16:01 UTC, Maxim Fomin wrote:
> On Thursday, 15 August 2013 at 00:57:26 UTC, Tommi wrote:
>> [..]
>> 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.

Agreed.

> Also actual conversion happens later in some completely 
> unrelated to type deduction compiler part.

I know implicit conversion happens at a later stage (not during 
type deduction). But I don't have any other words to describe it 
other than saying "implicit conversion during type deduction". If 
you can provide me some more exact language, please do.

On Thursday, 15 August 2013 at 07:16:01 UTC, Maxim Fomin wrote:
> On Thursday, 15 August 2013 at 00:57:26 UTC, Tommi wrote:
>> [..]
>> 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.

Why would the compiler need a hint? The compiler knows that the 
static array can implicitly convert to dynamic array, so it 
should be able to check if the function could be called with the 
argument first implicitly converted to a 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.

No, I'm not asking A -> C, I'm just asking that int[3] convert to 
int[]. I don't understand where you get this exponential 
increase. Since they are both built-in types, there can't be any 
increase: int[3] can never implicitly convert to some 
user-defined struct S, and int[] can never implicitly convert to 
anything.

On Thursday, 15 August 2013 at 07:16:01 UTC, Maxim Fomin wrote:
> On Thursday, 15 August 2013 at 00:57:26 UTC, Tommi wrote:
>> 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.

No, I don't mean making two-step conversions, just plain old 
one-step.


More information about the Digitalmars-d mailing list