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.

Reply via email to