www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Request: a more logical static array behavior

reply "Tommi" <tommitissari hotmail.com> writes:
Disclaimer: I'm going to be excruciatingly explicit here just so 
that everybody can follow my train of thought.

References:
1) Subtype/Supertype: http://en.wikipedia.org/wiki/Subtyping

2) Type deduction: 
http://channel9.msdn.com/Series/C9-Lectures-Stephan-T-Lavavej-Core-C-/Stephan-T-Lavavej-Core-C-2-of-n

3) Range: http://dlang.org/phobos/std_range.html#isInputRange

-------
e.g. = "for example"

Static array, e.g. int[3], is not a range.
Dynamic array, e.g. int[], is a range.

int[] is not a supertype of int[3].

Non-subtype type: "type that is not a subtype of any other type"

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.

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.

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.

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 think this would be a breaking change.


NOTE:
Subtypes can implicitly convert to their supertype during type 
deduction, there's nothing magical about that.
Aug 14 2013
next sibling parent "Tommi" <tommitissari hotmail.com> writes:
On Thursday, 15 August 2013 at 00:57:26 UTC, Tommi wrote:
 ...

And half the time I say "converted to int[]" I mean "converted to uint[]" and the other half of the time I mean "converted to char[]". Sorry about that.
Aug 14 2013
prev sibling next sibling parent "Tommi" <tommitissari hotmail.com> writes:
On Thursday, 15 August 2013 at 01:05:54 UTC, Tommi wrote:
 On Thursday, 15 August 2013 at 00:57:26 UTC, Tommi wrote:
 ...

And half the time I say "converted to int[]" I mean "converted to uint[]" and the other half of the time I mean "converted to char[]". Sorry about that.

Actually that's not true either. Whenever I say 'int' after the examples start, just think 'char'.
Aug 14 2013
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Thursday, August 15, 2013 02:57:25 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?

No. If anything, we should get rid of the implicit conversion from a static array to a dynamic one. It's actually unsafe to do so. It's just like if you implicitly converted a local variable to the address of that local variable when you passed it to a function that accepted a pointer. IMHO, it never should have been allowed in the first place. At least with taking the address of a local variable, the compiler treats it as system. The compiler doesn't currently do that with taking the slice of a static array. http://d.puremagic.com/issues/show_bug.cgi?id=8838 If you want a dynamic array from a static one, then slice it. That works just fine with templated functions, and makes what you want explicit. Also, making it so that IFTI instantiated templates with the dynamic array type when given a static array would make it so that you would have to explicitly instantiate any templates where you actually wanted to pass a static array, which is a definite negative IMHO. At this point, I don't really expect that it'll be changed so that static arrays do not implicitly convert to dynamic ones (much as it would be ideal to make that change), but I really don't think that we should do anything to make the problem worse by adding yet more such implicit conversions. - Jonathan M Davis
Aug 14 2013
prev sibling next sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
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.
Aug 15 2013
parent Artur Skawina <art.08.09 gmail.com> writes:
On 08/15/13 14:44, Tommi wrote:
[...]
 No, I'm not asking A -> C, I'm just asking that int[3] convert to int[].

From you earlier post:

Ret bar(R)(R r) // [6] if (std.range.isInputRange!R) { return Ret.input_range; } You'd like to be able to call 'bar' with a static array. Currently you can't, because 'R' becomes a /static array/, hence not a input range. Note that Ret baz(R)(R[] r) // [6] if (std.range.isInputRange!(R[])) { return Ret.input_range; } /would/ work. This case works, because 'baz' expects a dynamic array and static arrays implicitly convert to dynamic ones - so if there is no better fitting overload then the static->dynamic conversion will be done. To make your case work, it would be necessary to first deduce R==int[3], then try instantiating the template, and if this fails retry with whatever int[3] implicitly converts to (int[] in this case). The only alternative is making the static->dynamic array conversion /mandatory/ when deducing types - which is not a good idea either. The implicit int[3] -> int[] conversion should not exist. artur
Aug 15 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 15 August 2013 at 02:30:54 UTC, Jonathan M Davis 
wrote:
 On Thursday, August 15, 2013 02:57:25 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?

No. If anything, we should get rid of the implicit conversion from a static array to a dynamic one. It's actually unsafe to do so. It's just like if you implicitly converted a local variable to the address of that local variable when you passed it to a function that accepted a pointer. IMHO, it never should have been allowed in the first place. At least with taking the address of a local variable, the compiler treats it as system. The compiler doesn't currently do that with taking the slice of a static array. http://d.puremagic.com/issues/show_bug.cgi?id=8838 If you want a dynamic array from a static one, then slice it. That works just fine with templated functions, and makes what you want explicit. Also, making it so that IFTI instantiated templates with the dynamic array type when given a static array would make it so that you would have to explicitly instantiate any templates where you actually wanted to pass a static array, which is a definite negative IMHO. At this point, I don't really expect that it'll be changed so that static arrays do not implicitly convert to dynamic ones (much as it would be ideal to make that change), but I really don't think that we should do anything to make the problem worse by adding yet more such implicit conversions. - Jonathan M Davis

+1
Aug 15 2013
prev sibling next sibling parent "Tommi" <tommitissari hotmail.com> writes:
On Thursday, 15 August 2013 at 02:30:54 UTC, Jonathan M Davis 
wrote:
 On Thursday, August 15, 2013 02:57:25 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?

No. If anything, we should get rid of the implicit conversion from a static array to a dynamic one. It's actually unsafe to do so. It's just like if you implicitly converted a local variable to the address of that local variable when you passed it to a function that accepted a pointer. IMHO, it never should have been allowed in the first place. At least with taking the address of a local variable, the compiler treats it as system. The compiler doesn't currently do that with taking the slice of a static array. http://d.puremagic.com/issues/show_bug.cgi?id=8838 If you want a dynamic array from a static one, then slice it. That works just fine with templated functions, and makes what you want explicit. Also, making it so that IFTI instantiated templates with the dynamic array type when given a static array would make it so that you would have to explicitly instantiate any templates where you actually wanted to pass a static array, which is a definite negative IMHO. At this point, I don't really expect that it'll be changed so that static arrays do not implicitly convert to dynamic ones (much as it would be ideal to make that change), but I really don't think that we should do anything to make the problem worse by adding yet more such implicit conversions. - Jonathan M Davis

Now I feel like these three different notions are getting somewhat conflated: 1) memory safety 2) implicit conversion 3) implicit conversion during type deduction Memory safety ------------- If the following code is treated as system code (which it is): void getLocal(int* p) { } void main() { int n; getLocal(&n); } ...then the following code should be treated as system code as well (which it currently isn't): void getLocal(int[] da) { } void main() { int[5] sa; getLocal(sa[]); // Notice the _explicit_ conversion } ...There's no two ways about it. But implicit conversion has nothing to do with this. If you want to disallow implicit conversion because it's a bug prone programming construct, then you have a valid reason to do so (and it would be fine by me). But if you want to disallow implicit conversion from static array to a slice because it's not _always_ memory safe, then you're doing it for the wrong reason: e.g. the following code is memory safe even though we're using the implicit conversion: void getGlobal(int[] da) { } int[5] gsa; void main() { getGlobal(gsa); // implicit conversion } Like I said: implicit conversion doesn't really have anything to do with the potential memory safety issues. Implicit conversion VS Implicit conversion during type deduction ---------------------------------------------------------------- I don't think that you failed to see the distinction between these two things, but because someone might, I'll talk about this a bit more. This is regular implicit conversion (nothing weird or magical about it): void foo(int[] da) { } int[3] sa; foo(sa); // implicit conversion This is implicit conversion during type deduction (totally weird and magical): void foo(T)(T[] da) { } int[3] sa; foo(sa); // implicit conversion during type deduction That above example about implicit conversion during type deduction is like writing the following C++ code and having it actually compile: template <typename T> struct DynamicArray { }; template <typename T> struct StaticArray { operator DynamicArray<T>() const { return DynamicArray<T>{}; } }; template <typename T> void foo(DynamicArray<T> da) { } void bar(DynamicArray<int> da) { } int main(int argc, char *argv[]) { StaticArray<int> sa; foo((DynamicArray<int>)sa); // OK: explicit conversion bar(sa); // OK: regular implicit conversion foo(sa); // Error: No matching function call to 'foo' return 0; } It is this implicit conversion during type deduction that makes D's static arrays' behavior illogical and inconsistent (because it doesn't happen in all type deduction contexts). Whereas regular implicit conversion may be a dangerous or an unsafe programming tool, there's nothing illogical about it. I don't want to increase the number of implicit conversions. All I'm trying to do is make D's static arrays behave more logically. And there are two ways to do this: 1) make static arrays free to implicitly convert to dynamic array in all type deduction situations 2) disallow static arrays from implicitly converting during type deduction Notice that in order to make static arrays' behavior logical, there's no need to disallow them from implicitly converting to dynamic arrays in the general sense (just during type deduction).
Aug 15 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Thursday, 15 August 2013 at 02:30:54 UTC, Jonathan M Davis 
wrote:
 No. If anything, we should get rid of the implicit conversion 
 from a static
 array to a dynamic one. It's actually unsafe to do so. It's 
 just like if you
 implicitly converted a local variable to the address of that 
 local variable
 when you passed it to a function that accepted a pointer.

scope, scope, scope! ;)
Aug 15 2013
prev sibling next sibling parent "Tommi" <tommitissari hotmail.com> writes:
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.
Aug 15 2013
prev sibling next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Thursday, 15 August 2013 at 12:12:59 UTC, Tommi wrote:
 Implicit conversion VS Implicit conversion during type deduction
 ----------------------------------------------------------------
 I don't think that you failed to see the distinction between 
 these two things, but because someone might, I'll talk about 
 this a bit more.

 This is regular implicit conversion (nothing weird or magical 
 about it):

 void foo(int[] da) { }
 int[3] sa;
 foo(sa); // implicit conversion

 This is implicit conversion during type deduction (totally 
 weird and magical):

 void foo(T)(T[] da) { }
 int[3] sa;
 foo(sa); // implicit conversion during type deduction

Please stop spreading this misconveption. There is *no* conversion during type deduction. There is *a check* whether base type of static array is same as base type of dynamic array which happens to be true in this case. *Conversion* happens in completely related compiler part. And there is no special about it during template type deduction. This (meaning that base type of int[N] array is same as base type of int[] array) happens or could happen in any stage of compiling proccess. How C++ does it is irrelevant to what D does.
Aug 15 2013
prev sibling next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Thursday, 15 August 2013 at 12:44:09 UTC, Tommi wrote:
 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
 }

OK, void getLong(T)(T arg) if (is(T : long)) { } void main() { int n; getLong(n); // int is implicitly convertible to long } now you have "implicit conversion from int to long during type deduction".
 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.

There is a test whether base types are equal (which happens in many stages, including type deduction) and conversion which happens in later stage.
 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.

Because I was speaking about general case. In this case yes, dmd can know beforehand that T[N] can be converted to T[]. In general case which can involve alias this (including multiple alias this) the problem can be more complex.
Aug 15 2013
prev sibling next sibling parent "Tommi" <tommitissari hotmail.com> writes:
On Thursday, 15 August 2013 at 13:25:58 UTC, Maxim Fomin wrote:
 On Thursday, 15 August 2013 at 12:12:59 UTC, Tommi wrote:
 Implicit conversion VS Implicit conversion during type 
 deduction
 ----------------------------------------------------------------
 I don't think that you failed to see the distinction between 
 these two things, but because someone might, I'll talk about 
 this a bit more.

 This is regular implicit conversion (nothing weird or magical 
 about it):

 void foo(int[] da) { }
 int[3] sa;
 foo(sa); // implicit conversion

 This is implicit conversion during type deduction (totally 
 weird and magical):

 void foo(T)(T[] da) { }
 int[3] sa;
 foo(sa); // implicit conversion during type deduction

Please stop spreading this misconveption. There is *no* conversion during type deduction. There is *a check* whether base type of static array is same as base type of dynamic array which happens to be true in this case. *Conversion* happens in completely related compiler part.

I've been saying "implicit conversion during type deduction", but I seriously doubt that anyone who knows what type deduction is, would think that actual implicit conversion somehow happens during that. (Type deduction is simply figuring out what the actual type of a templated type is given a certain context). But, from now on, I'll use the phrase "checking for implicit conversions during type deduction" instead of "implicit conversion during type deduction". On Thursday, 15 August 2013 at 13:25:58 UTC, Maxim Fomin wrote:
 And there is no special about it during template type deduction.
 This (meaning that base type of int[N] array is same as base 
 type
 of int[] array) happens or could happen in any stage of 
 compiling
 proccess. How C++ does it is irrelevant to what D does.

I agree that what C++ does is irrelevant to what D does (I never said it was). I used an example of C++ code to make a point which _is_ relevant to D. Since you seemed to miss the point, I'm going to translate that previous C++ example code D code now to get my point across: struct DynamicArray(T) { } struct StaticArray(T, size_t n) { DynamicArray!T opImplicitCast() const { return DynamicArray!T(); } } void foo(T)(DynamicArray!T da) { } void bar(DynamicArray!int da) { } void main() { StaticArray!(int, 5) sa; bar(sa); // OK: implicit conversion foo(cast(DynamicArray!int) sa); // OK: explicit conversion foo(sa); // Error: No matching function call to 'foo' } Don't try to compile that, it won't work because I used the opImplicitCast operator which is a future feature of D (it provides an implicit conversion for used defined types). How do I know it's a future feature of D? Don't ask... okay, you got me... I'm a time traveller. Now, to fulfill my promise of being excruciatingly explicit: What said before about being a time traveller, it was a joke. My point is that D could have an implicit cast operator in the future. And if it did have it, then it would become obvious to everybody why it is that a static array, such as: int[5] ...is magical, that is, it is fundamentally different from: StaticArray!(int, 5) ...in that whereas the above code example would _not_ compile, this next example would (and it does) compile: void foo(T)(T[] da) { } void bar(int[] da) { } void main() { int[5] sa; bar(sa); // OK: implicit conversion foo(cast(int[]) sa); // OK: explicit conversion foo(sa); // OK !!! (compare to the previous example) }
Aug 15 2013
prev sibling next sibling parent "Tommi" <tommitissari hotmail.com> writes:
On Thursday, 15 August 2013 at 13:50:45 UTC, Maxim Fomin wrote:
 On Thursday, 15 August 2013 at 12:44:09 UTC, Tommi wrote:
 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
 }

OK, void getLong(T)(T arg) if (is(T : long)) { } void main() { int n; getLong(n); // int is implicitly convertible to long } now you have "implicit conversion from int to long during type deduction".

No it's not: void getLong(T)(T arg) if (is(T : long)) { static assert(is(typeof(arg) == int)); } void main() { int n; getLong(n); // int is _not_ implicitly converted to long }
Aug 15 2013
prev sibling next sibling parent "Tommi" <tommitissari hotmail.com> writes:
On Thursday, 15 August 2013 at 13:53:17 UTC, Artur Skawina wrote:
 On 08/15/13 14:44, Tommi wrote:
 [...]
 No, I'm not asking A -> C, I'm just asking that int[3] convert 
 to int[].

From you earlier post:

Ret bar(R)(R r) // [6] if (std.range.isInputRange!R) { return Ret.input_range; } You'd like to be able to call 'bar' with a static array. Currently you can't, because 'R' becomes a /static array/, hence not a input range. Note that Ret baz(R)(R[] r) // [6] if (std.range.isInputRange!(R[])) { return Ret.input_range; } [..]

To be exact, I want either of the following options (but not both of them): 1) I want to be able to call 'bar' with a static array OR 2) I want to _not_ be able to call 'baz' with a static array Either one of those options is fine by me. All I want is make D's static arrays behave logically (and either one of those options would do it).
Aug 15 2013
prev sibling next sibling parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Thursday, 15 August 2013 at 14:32:29 UTC, Tommi wrote:
 No it's not:

 void getLong(T)(T arg)
 if (is(T : long))
 {
     static assert(is(typeof(arg) == int));
 }

 void main()
 {
     int n;
     getLong(n); // int is _not_ implicitly converted to long
 }

Yes, because during type deduction there was constraint test that checked whether int is convertible to long which is the same story as in static-dynamic array case.
Aug 15 2013
prev sibling next sibling parent "Tommi" <tommitissari hotmail.com> writes:
On Thursday, 15 August 2013 at 14:53:08 UTC, Maxim Fomin wrote:
 On Thursday, 15 August 2013 at 14:32:29 UTC, Tommi wrote:
 No it's not:

 void getLong(T)(T arg)
 if (is(T : long))
 {
    static assert(is(typeof(arg) == int));
 }

 void main()
 {
    int n;
    getLong(n); // int is _not_ implicitly converted to long
 }

Yes, because during type deduction there was constraint test that checked whether int is convertible to long which is the same story as in static-dynamic array case.

The code snippet above is not the same thing as what happens in the static-dynamic array case. In the above code snippet the type deduction for 'T' during the instantiation of 'getLong' has already finished by the time the template constraint is evaluated (how could the template constraint be evaluated if the actual type for 'T' hadn't already been deduced?). So, the compiler doesn't consider the implicit conversion from int to long _during_ type deduction, but after it. The only time when the compiler is willing to consider the possible implicit conversions during type deduction is with static arrays: hence... "magic".
Aug 15 2013
prev sibling parent "Tommi" <tommitissari hotmail.com> writes:
On Thursday, 15 August 2013 at 15:07:23 UTC, Tommi wrote:
 The only time when the compiler is willing to consider the 
 possible implicit conversions during type deduction is with 
 static arrays: hence... "magic".

Barring this special case which I mentioned in my original post: On Thursday, 15 August 2013 at 00:57:26 UTC, Tommi wrote:
 NOTE:
 Subtypes can implicitly convert to their supertype during type 
 deduction, there's nothing magical about that.

Here's an example of that: class SuperClass(T) { } class SubClass(T) : SuperClass!T { } struct Supertype(T) { } struct Subtype(T) { Supertype!T s; alias s this; } void foo(T)(SuperClass!T superc) { } void bar(T)(Supertype!T supert) { } void main() { SubClass!int subc; foo(subc); // OK Subtype!int subt; bar(subt); // OK } Although, it might be a bit misleading to call that implicit conversion, because nothing is actually converted: it's just that an entity is interpreted as something else, which it also is.
Aug 15 2013