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.