digitalmars.D - Request: a more logical static array behavior
- Tommi (78/78) Aug 14 2013 Disclaimer: I'm going to be excruciatingly explicit here just so
- Tommi (4/5) Aug 14 2013 And half the time I say "converted to int[]" I mean "converted to
- Tommi (3/8) Aug 14 2013 Actually that's not true either. Whenever I say 'int' after the
- Jonathan M Davis (20/24) Aug 14 2013 No. If anything, we should get rid of the implicit conversion from a sta...
- monarch_dodra (3/42) Aug 15 2013 +1
- Tommi (93/132) Aug 15 2013 Now I feel like these three different notions are getting
- Maxim Fomin (10/25) Aug 15 2013 Please stop spreading this misconveption. There is *no*
- Tommi (57/92) Aug 15 2013 I've been saying "implicit conversion during type deduction", but
- Dicebot (4/11) Aug 15 2013 scope, scope, scope!
- Maxim Fomin (24/85) Aug 15 2013 I don't understand why are you surprising that int[3] can be
- Tommi (35/138) Aug 15 2013 I don't expect int[3] to implicitly convert to int[] during type
- Maxim Fomin (21/48) Aug 15 2013 OK,
- Tommi (12/44) Aug 15 2013 No it's not:
- Maxim Fomin (4/15) Aug 15 2013 Yes, because during type deduction there was constraint test that
- Artur Skawina (26/28) Aug 15 2013 Ret bar(R)(R r) // [6]
- Tommi (9/30) Aug 15 2013 To be exact, I want either of the following options (but not both
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
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
On Thursday, 15 August 2013 at 01:05:54 UTC, Tommi wrote:On Thursday, 15 August 2013 at 00:57:26 UTC, Tommi wrote:Actually that's not true either. Whenever I say 'int' after the examples start, just think 'char'....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
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
On Thursday, 15 August 2013 at 02:30:54 UTC, Jonathan M Davis wrote:On Thursday, August 15, 2013 02:57:25 Tommi wrote:+1Thus, 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 15 2013
On Thursday, 15 August 2013 at 02:30:54 UTC, Jonathan M Davis wrote:On Thursday, August 15, 2013 02:57:25 Tommi wrote: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).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 15 2013
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 deductionPlease 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
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: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: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 deductionPlease 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.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
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
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
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: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: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.On Thursday, 15 August 2013 at 00:57:26 UTC, Tommi wrote:Agreed.[..] 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.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: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.[..] 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.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:No, I don't mean making two-step conversions, just plain old one-step.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
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".There is a test whether base types are equal (which happens in many stages, including type deduction) and conversion which happens in later stage.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.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.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.
Aug 15 2013
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: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 }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".
Aug 15 2013
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
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: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".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
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
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
On Thursday, 15 August 2013 at 13:53:17 UTC, Artur Skawina wrote:On 08/15/13 14:44, Tommi wrote: [...]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).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; } [..]
Aug 15 2013