digitalmars.D - Function templates do implicit conversions for their arguments
- TommiT (59/59) Jul 02 2013 This is a pretty big delta between C++ and D. It's going to
- TommiT (3/9) Jul 02 2013 That should be:
- Jesse Phillips (23/38) Jul 02 2013 C++ doesn't have alias this. The behavior that it should be
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (6/8) Jul 02 2013 But 'alias this' is also for automatic type conversions. TommiT's had
- TommiT (37/60) Jul 02 2013 Okay. I had thought of "alias this" as *merely* implicit
- Maxim Fomin (31/32) Jul 02 2013 Slightly changed original code
- TommiT (14/16) Jul 02 2013 I had started to think about "alias this" as C++'s implicit
- TommiT (25/25) Jul 03 2013 Apparently I'm correct with my initial assertion after all, but
- Maxim Fomin (18/43) Jul 03 2013 "at the same time implicit conversions and type deduction"
- TommiT (29/78) Jul 04 2013 Yes, you are right in that the quote from TDPL refers to that
- TommiT (31/32) Jul 04 2013 No need for that. I'll explain what that quote means.
- Maxim Fomin (13/24) Jul 04 2013 You heavily misunderstoond the topic. The issue here is that in
- TommiT (9/33) Jul 04 2013 Yes I understand this perfectly. No problem. This works exactly
- Maxim Fomin (24/60) Jul 04 2013 There should be some conversion about how to make judgments based
- TommiT (30/54) Jul 04 2013 Do you mean that if D had the C++ style implicit conversion
- TommiT (6/15) Jul 04 2013 Let me clarify that arguably silly looking syntax. The @implicit
- Maxim Fomin (33/87) Jul 04 2013 Your implicit syntax is redundant. What C++ does is irrelevant. D
- TommiT (46/125) Jul 04 2013 My implicit cast operator syntax is not redundant because it's
- Maxim Fomin (13/33) Jul 04 2013 The idea that situation with alias this and arrays is
- TommiT (44/83) Jul 04 2013 Is-a relationship between types means this type of thing:
- TommiT (6/10) Jul 04 2013 That was supposed to be:
- TommiT (5/10) Jul 04 2013 Although, that's not exactly true. C++ accepts an inexact match
- Maxim Fomin (11/27) Jul 04 2013 And this is a problem, because many of such naive judgemnets are
- TommiT (10/17) Jul 04 2013 Well, it doesn't really matter how it is implemented. What
- Maxim Fomin (9/28) Jul 04 2013 Issue in this case is not that it happens per se (of course, it
- TommiT (11/42) Jul 05 2013 Of course implicit conversion influences type deduction. If it
This is a pretty big delta between C++ and D. It's going to surprise everybody coming from C++, especially when it says in TDPL (page 140) that: "However, having the language attempt combinatorially at the same time implicit conversions and type deduction is a dicey proposition in the general case, so D does not attempt to do all that". D --- struct Wrap(Gift) { Gift gift; } struct Teddy { int id; Wrap!Teddy getWrapped() property { return Wrap!Teddy(this); } alias getWrapped this; } Gift tearOpen(Gift)(Wrap!Gift wrappedGift) { return wrappedGift.gift; } void main() { auto ted = Teddy(123); auto r = tearOpen(ted); // NOOOO! Teddy! assert(r == ted); // Phew, Teddy was implicitly gift-wrapped // and we tore the wrap open, not Teddy. } C++ --- template <typename Gift> struct Wrap { Gift gift; }; struct Teddy { int id; operator Wrap<Teddy>() { return Wrap<Teddy>{*this}; } }; template <typename Gift> Gift tearOpen(Wrap<Gift> wrappedGift) { return wrappedGift.gift; } int main() { Teddy ted (123); tearOpen(ted); // No matching function call to 'tearOpen' } This difference between D and C++ should be noted somewhere in the documentation with big red letters.
Jul 02 2013
On Tuesday, 2 July 2013 at 16:59:50 UTC, TommiT wrote:[..] C++ --- [..] Teddy ted (123); [..]That should be: Teddy ted {123};
Jul 02 2013
On Tuesday, 2 July 2013 at 16:59:50 UTC, TommiT wrote:D --- struct Wrap(Gift) { Gift gift; } struct Teddy { int id; Wrap!Teddy getWrapped() property { return Wrap!Teddy(this); } alias getWrapped this; }C++ doesn't have alias this. The behavior that it should be simulating is inheritance, I'd probably fail writing C++ for this so here is some D code to translate: import std.stdio; class Wrap(Gift) { abstract Gift gift(); } class Teddy : Wrap!Teddy { int id; this(int i) { id = i; } override Teddy gift() { return this; } } Gift tearOpen(Gift)(Wrap!Gift wrappedGift) { return wrappedGift.gift; } void main() { auto ted = new Teddy(123); auto r = tearOpen(ted); // NOOOO! Teddy! assert(r == ted); // Phew, Teddy was implicitly gift-wrapped // and we tore the wrap open, not Teddy. }
Jul 02 2013
On 07/02/2013 11:46 AM, Jesse Phillips wrote:C++ doesn't have alias this. The behavior that it should be simulating is inheritanceBut 'alias this' is also for automatic type conversions. TommiT's had implemented 'operator Wrap<Teddy>() const' (const added by me) but C++ does not attempt that automatic type conversion. D does attempt the conversion. I think that is TommiT's point. Ali
Jul 02 2013
On Tuesday, 2 July 2013 at 18:47:00 UTC, Jesse Phillips wrote:[..] The behavior that it [alias this] should be simulating is inheritance, [..]Okay. I had thought of "alias this" as *merely* implicit conversion. But it really makes sense that it simulates (models) inheritance and the implicit conversion (to the "base" type) is just a consequence of that. On Tuesday, 2 July 2013 at 18:47:00 UTC, Jesse Phillips wrote:[..] I'd probably fail writing C++ for this so here is some D code to translate: import std.stdio; class Wrap(Gift) { abstract Gift gift(); } class Teddy : Wrap!Teddy { int id; this(int i) { id = i; } override Teddy gift() { return this; } } Gift tearOpen(Gift)(Wrap!Gift wrappedGift) { return wrappedGift.gift; } void main() { auto ted = new Teddy(123); auto r = tearOpen(ted); // NOOOO! Teddy! assert(r == ted); // Phew, Teddy was implicitly gift-wrapped // and we tore the wrap open, not Teddy. }Here's what the corresponding code would be in C++: #include <cassert> template <typename Gift> class Wrap { public: virtual Gift gift() = 0; }; class Teddy : public Wrap<Teddy> { public: int id; Teddy(int i) : id(i) { } Teddy gift() { return *this; } bool operator==(const Teddy& other) const { return id == other.id; } }; template <typename Gift> Gift tearOpen(Wrap<Gift>& wrappedGift) { return wrappedGift.gift(); } int main() { auto ted = Teddy(123); auto r = tearOpen(ted); // OK assert(r == ted); // OK return 0; }
Jul 02 2013
On Tuesday, 2 July 2013 at 16:59:50 UTC, TommiT wrote:...Slightly changed original code struct Wrap(T) { T t; } struct S { int id; Wrap!S getWrapped() { return Wrap!S(this); } alias getWrapped this; } T tearOpen(T)(Wrap!T wrappedT) { return wrappedT.t; } void main() { S ted = S(123); S r = tearOpen(ted); assert(r == ted); } Since both S(123) and tearOpen(ted) has same type and return same value comparison succeeds. tearOpen(ted) should take Wrap!T but argument has different type. Argument has alias this, so it is analyzed and since it is aliased to Wrap!S, passing succeeds. This is how alias this is designed to work. What have you surprised here?
Jul 02 2013
On Tuesday, 2 July 2013 at 19:39:56 UTC, Maxim Fomin wrote:[..] This is how alias this is designed to work. What have you surprised here?I had started to think about "alias this" as C++'s implicit conversion operator. And I remembered wrong how "alias this" was explained in TDPL. I remembered it somehow like this: "Whenever a variable der of type Derived is used where a type Base is expected, the compiler tries der.getBase also." (assuming "alias getBase this;" in Derived) And since a templated parameter doesn't *expect* anything, I figured it wouldn't convert. But "alias this" is defined in TDPL (page 265) like so: "The workings of alias payload this are quite simple. Whenever a value obj of type Final!T is used in a context that would be illegal for its type, the compiler rewrites obj as obj.payload." Just an honest mistake on my part.
Jul 02 2013
Apparently I'm correct with my initial assertion after all, but only as it relates to implicit conversion from static to dynamic arrays. Let me start this thread again by using my initial opening statement: This is a pretty big delta between C++ and D. It's going to surprise everybody coming from C++, especially when it says in TDPL (page 140) that: "However, having the language attempt combinatorially at the same time implicit conversions and type deduction is a dicey proposition in the general case, so D does not attempt to do all that". Now, here's a new example: void foo(T)(T[] slice) { } void main() { int[10] arr; foo(arr); } See what I mean? int[10] is a distinct type from int[], so an implicit conversion must happen before 'arr' is passed to 'foo'. Implicit conversions never happen for arguments passed to templated functions in C++ (and neither in D according to that quote from TDPL above). And I'll just finish with my initial closing argument: This difference between D and C++ should be noted somewhere in the documentation with big red letters.
Jul 03 2013
On Wednesday, 3 July 2013 at 20:33:26 UTC, TommiT wrote:Apparently I'm correct with my initial assertion after all, but only as it relates to implicit conversion from static to dynamic arrays. Let me start this thread again by using my initial opening statement: This is a pretty big delta between C++ and D. It's going to surprise everybody coming from C++, especially when it says in TDPL (page 140) that: "However, having the language attempt combinatorially at the same time implicit conversions and type deduction is a dicey proposition in the general case, so D does not attempt to do all that"."at the same time implicit conversions and type deduction" Quoted comment from TDPL is related to template: T[] find(T)(T[] haystack, T needle) which means that base type of T[] and T must match.Now, here's a new example: void foo(T)(T[] slice) { } void main() { int[10] arr; foo(arr); }and this template has single argument.See what I mean? int[10] is a distinct type from int[], so an implicit conversion must happen before 'arr' is passed to 'foo'. Implicit conversions never happen for arguments passed to templated functions in C++ (and neither in D according to that quote from TDPL above).Surprise, following implicit conversions are happen all over the D. - pointer type to void type; - derived class to base class; - static array to dynamic array; - class implementator to interface; - enum to base type; - base type to aliased type; - ... and much more.And I'll just finish with my initial closing argument: This difference between D and C++ should be noted somewhere in the documentation with big red letters.Initial closing argument is based on incorrect understanding of the quote. Instead of comparing C++ and D it is better to read carefully spec and TDPL.
Jul 03 2013
On Thursday, 4 July 2013 at 04:52:13 UTC, Maxim Fomin wrote:On Wednesday, 3 July 2013 at 20:33:26 UTC, TommiT wrote:Yes, you are right in that the quote from TDPL refers to that specific function signature and is saying that the base type of T[] and T must match. But more generally, that quote is also saying that D doesn't try to do implicit conversion and type deduction at the same time for type-parameterized runtime arguments. In other words, the quote is saying: the type of the argument you pass to a templated function must match exactly to the templated type that the function template is expecting for that particular argument. That is: no implicit conversion happens to your variable before it is passed to the function as a runtime argument whose type is parameterized by the function. On Thursday, 4 July 2013 at 04:52:13 UTC, Maxim Fomin wrote:Apparently I'm correct with my initial assertion after all, but only as it relates to implicit conversion from static to dynamic arrays. Let me start this thread again by using my initial opening statement: This is a pretty big delta between C++ and D. It's going to surprise everybody coming from C++, especially when it says in TDPL (page 140) that: "However, having the language attempt combinatorially at the same time implicit conversions and type deduction is a dicey proposition in the general case, so D does not attempt to do all that"."at the same time implicit conversions and type deduction" Quoted comment from TDPL is related to template: T[] find(T)(T[] haystack, T needle) which means that base type of T[] and T must match.On Wednesday, 3 July 2013 at 20:33:26 UTC, TommiT wrote:But that's not relevant as I explained above. On Thursday, 4 July 2013 at 04:52:13 UTC, Maxim Fomin wrote:Now, here's a new example: void foo(T)(T[] slice) { } void main() { int[10] arr; foo(arr); }and this template has single argument.On Wednesday, 3 July 2013 at 20:33:26 UTC, TommiT wrote:Okay, my wording was not the best possible there. I can see that what I wrote could be misinterpreted. I was _not_ saying that C++ doesn't do implicit conversions all over the place (or that D doesn't). Actually, C++ probably does more implicit conversions than D does. I was just saying that implicit conversion never happens in C++ for a variable that is passed to a function as an argument whose type is fully or partly parameterized by that function. And this is a big difference between the two languages which should be emphasised somewhere in the documentation and that quote should be fixed in the next edition of TDPL. On Thursday, 4 July 2013 at 04:52:13 UTC, Maxim Fomin wrote:See what I mean? int[10] is a distinct type from int[], so an implicit conversion must happen before 'arr' is passed to 'foo'. Implicit conversions never happen for arguments passed to templated functions in C++ (and neither in D according to that quote from TDPL above).Surprise, following implicit conversions are happen all over the D. - pointer type to void type; - derived class to base class; - static array to dynamic array; - class implementator to interface; - enum to base type; - base type to aliased type; - ... and much more.On Wednesday, 3 July 2013 at 20:33:26 UTC, TommiT wrote:Perhaps Andrei could tell us what that quote means. Or perhaps you could show me the part of the spec which I should have read more carefully.And I'll just finish with my initial closing argument: This difference between D and C++ should be noted somewhere in the documentation with big red letters.Initial closing argument is based on incorrect understanding of the quote. Instead of comparing C++ and D it is better to read carefully spec and TDPL.
Jul 04 2013
On Thursday, 4 July 2013 at 09:24:53 UTC, TommiT wrote:[..] Perhaps Andrei could tell us what that quote means. [..]No need for that. I'll explain what that quote means. Here's that quote again: "However, having the language attempt combinatorially at the same time implicit conversions and type deduction is a dicey proposition in the general case, so D does not attempt to do all that." Here's a simpler paraphrasing of that quote: "D doesn't attempt to do implicit conversion and type deduction at the same time." In this context, "type deduction" means the process of trying to figure out what kind of a signature a function template should instantiate to, in other words, what the template parameters of the instantiated function should be. For example, given a function template: void foo(T)(Array!T a) { } ...and a call which forces that function template to instantiate: Array!int arr; foo(arr); // OK Type deduction is able to figure out that T must be int, and instantiates the function template to: void foo(Array!int a) { } But, if you try to pass to foo a variable of some user defined type MyType which merely implicitly converts Array!int, then the type deduction fails, because "D doesn't attempt to do implicit conversion and type deduction at the same time". MyType mt; foo(mt); // Error Now, we can't test this because D doesn't have an implicit conversion operator (like C++ does), but it could have it in the future, and that's not really even relevant.
Jul 04 2013
On Thursday, 4 July 2013 at 09:24:53 UTC, TommiT wrote:Yes, you are right in that the quote from TDPL refers to that specific function signature and is saying that the base type of T[] and T must match. But more generally, that quote is also saying that D doesn't try to do implicit conversion and type deduction at the same time for type-parameterized runtime arguments. In other words, the quote is saying: the type of the argument you pass to a templated function must match exactly to the templated type that the function template is expecting for that particular argument. That is: no implicit conversion happens to your variable before it is passed to the function as a runtime argument whose type is parameterized by the function.You heavily misunderstoond the topic. The issue here is that in T[] find(T)(T[] haystack, T needle) type of neendle should correspond to base type of haystack. If there is a contradiction ("at the same time implicit conversions and type deduction"), dmd issues error. But here void foo(T)(T[] slice) { } base type of slice is not tied to any other parameters. Actually if you pass integer static array, dmd deduces T to be int, then template instantiation part is done. After that static array is casted to slice as what happens with non-template function (internally dmd treats it like foo(cast(int[])arr)). Other your comments are based on this misunderstanding.
Jul 04 2013
On Thursday, 4 July 2013 at 13:45:07 UTC, Maxim Fomin wrote:On Thursday, 4 July 2013 at 09:24:53 UTC, TommiT wrote:No I didn't.Yes, you are right in that the quote from TDPL refers to that specific function signature and is saying that the base type of T[] and T must match. But more generally, that quote is also saying that D doesn't try to do implicit conversion and type deduction at the same time for type-parameterized runtime arguments. In other words, the quote is saying: the type of the argument you pass to a templated function must match exactly to the templated type that the function template is expecting for that particular argument. That is: no implicit conversion happens to your variable before it is passed to the function as a runtime argument whose type is parameterized by the function.You heavily misunderstoond the topic.The issue here is that in T[] find(T)(T[] haystack, T needle) type of neendle should correspond to base type of haystack. If there is a contradiction ("at the same time implicit conversions and type deduction"), dmd issues error.Yes I understand this perfectly. No problem. This works exactly like it does in C++ and I know C++. Trust me.Actually if you pass integer static array, dmd deduces T to be int, [..]And that right there, "dmd deduces T to be int", is the crux of the matter. How on earth is DMD able to deduce T to be int, without using the implicit conversion from int[10] to int[] ? DMD does the implicit conversion int[10] -> int[] while it is doing type deduction, which according to TDPL shouldn't happen.
Jul 04 2013
On Thursday, 4 July 2013 at 13:55:17 UTC, TommiT wrote:On Thursday, 4 July 2013 at 13:45:07 UTC, Maxim Fomin wrote:There should be some conversion about how to make judgments based on arguments, otherwise loop of "No ..." can be indefinitely long. You argue that in code void foo(T)(T[] array) {} if static array is passed, there is violation of one quote from TDPL. You are wrong, because: 1) You incorrectly applied quote regarding code void foo(T)(T[] ar, T t){} to a different situation. In this case t is tied to some type, in case we discussed, it doesn't. 2) In case of one parameter, a variable isn't tied to any type and usual implicit conversions are applied.On Thursday, 4 July 2013 at 09:24:53 UTC, TommiT wrote:No I didn't.Yes, you are right in that the quote from TDPL refers to that specific function signature and is saying that the base type of T[] and T must match. But more generally, that quote is also saying that D doesn't try to do implicit conversion and type deduction at the same time for type-parameterized runtime arguments. In other words, the quote is saying: the type of the argument you pass to a templated function must match exactly to the templated type that the function template is expecting for that particular argument. That is: no implicit conversion happens to your variable before it is passed to the function as a runtime argument whose type is parameterized by the function.You heavily misunderstoond the topic.Style in which you are arguing is an argument to do not.The issue here is that in T[] find(T)(T[] haystack, T needle) type of neendle should correspond to base type of haystack. If there is a contradiction ("at the same time implicit conversions and type deduction"), dmd issues error.Yes I understand this perfectly. No problem. This works exactly like it does in C++ and I know C++. Trust me.DMD is stupid, but not that. If it has T[] parameter, and int[10] static array which is convertible to int[] is passed, T is deduced to be int. What other types T can be? A float, object, or pointer to union?Actually if you pass integer static array, dmd deduces T to be int, [..]And that right there, "dmd deduces T to be int", is the crux of the matter. How on earth is DMD able to deduce T to be int, without using the implicit conversion from int[10] to int[] ?DMD does the implicit conversion int[10] -> int[] while it is doing type deduction, which according to TDPL shouldn't happen.This is flawed since you can: int[10] arr; foo!int(arr). Here there is no deduction puzzle, as parameter was passed explicitly and usual conversion was applied as in case of non-template function. And if you argue, that this should not happen, than you argue to make explicit "!int" typing which is absolutely redundant in this case.
Jul 04 2013
On Thursday, 4 July 2013 at 15:03:54 UTC, Maxim Fomin wrote:[..] 2) In case of one parameter, a variable isn't tied to any type and usual implicit conversions are applied.Do you mean that if D had the C++ style implicit conversion operator (using let's say the keyword ' implicit'), then the following would compile? struct Wrap(T) { T t; } struct Toy { alias Wrapped = Wrap!Toy; implicit Wrapped opCast(T : Wrapped)() { return Wrapped.init; } } void foo(T)(Wrap!T) { } void main() { foo(Toy.init); } On Thursday, 4 July 2013 at 15:03:54 UTC, Maxim Fomin wrote:On Thursday, 4 July 2013 at 13:55:17 UTC, TommiT wrote:So you admit that DMD does implicit conversion during type deduction? On Thursday, 4 July 2013 at 15:03:54 UTC, Maxim Fomin wrote:On Thursday, 4 July 2013 at 13:45:07 UTC, Maxim Fomin wrote:DMD is stupid, but not that. If it has T[] parameter, and int[10] static array which is convertible to int[] is passed, T is deduced to be int. What other types T can be? A float, object, or pointer to union?Actually if you pass integer static array, dmd deduces T to be int, [..]And that right there, "dmd deduces T to be int", is the crux of the matter. How on earth is DMD able to deduce T to be int, without using the implicit conversion from int[10] to int[] ?On Thursday, 4 July 2013 at 13:55:17 UTC, TommiT wrote:What exactly in what I said there is flawed? Your example foo!int(arr) has nothing to do with what I said, because there's no type deduction in your example. On Thursday, 4 July 2013 at 15:03:54 UTC, Maxim Fomin wrote:DMD does the implicit conversion int[10] -> int[] while it is doing type deduction, which according to TDPL shouldn't happen.This is flawed since you can: int[10] arr; foo!int(arr).[..] And if you argue, that this should not happen, than you argue to make explicit "!int" typing which is absolutely redundant in this case.What on earth made you think that I would argue for such idiocy.
Jul 04 2013
On Thursday, 4 July 2013 at 15:59:21 UTC, TommiT wrote:struct Toy { alias Wrapped = Wrap!Toy; implicit Wrapped opCast(T : Wrapped)() { return Wrapped.init; } }Let me clarify that arguably silly looking syntax. The implicit opCast operator simply means that any instance of Toy is implicitly convertible to an instance of Wrapped!Toy, exactly like any instance of type int[10] is implicitly convertible to an instance of type int[].
Jul 04 2013
On Thursday, 4 July 2013 at 15:59:21 UTC, TommiT wrote:On Thursday, 4 July 2013 at 15:03:54 UTC, Maxim Fomin wrote:Your implicit syntax is redundant. What C++ does is irrelevant. D has alias this. import std.stdio; struct Wrap(T) { T t; } struct Toy { alias get this; Wrap!Toy get() { return Wrap!Toy.init; } } void foo(T)(Wrap!T t) { writeln(T.stringof); } void main() { foo(Toy.init); } Note, that T is Toy, so there were no type conversion during template instantiation. There was argument conversion after instantiation, as it happens usually. Back to foo function accepting slice - dmd does the same thing.[..] 2) In case of one parameter, a variable isn't tied to any type and usual implicit conversions are applied.Do you mean that if D had the C++ style implicit conversion operator (using let's say the keyword ' implicit'), then the following would compile? struct Wrap(T) { T t; } struct Toy { alias Wrapped = Wrap!Toy; implicit Wrapped opCast(T : Wrapped)() { return Wrapped.init; } } void foo(T)(Wrap!T) { } void main() { foo(Toy.init); }On Thursday, 4 July 2013 at 15:03:54 UTC, Maxim Fomin wrote:See above. What type implicit converision did dmd in case of int[10] and int[]. Conversion from int to int?On Thursday, 4 July 2013 at 13:55:17 UTC, TommiT wrote:So you admit that DMD does implicit conversion during type deduction?On Thursday, 4 July 2013 at 13:45:07 UTC, Maxim Fomin wrote:DMD is stupid, but not that. If it has T[] parameter, and int[10] static array which is convertible to int[] is passed, T is deduced to be int. What other types T can be? A float, object, or pointer to union?Actually if you pass integer static array, dmd deduces T to be int, [..]And that right there, "dmd deduces T to be int", is the crux of the matter. How on earth is DMD able to deduce T to be int, without using the implicit conversion from int[10] to int[] ?On Thursday, 4 July 2013 at 15:03:54 UTC, Maxim Fomin wrote:Example shows that implicit conversion on argument in this case has nothing with type deduction (there is no type deduction, yet argument was converted).On Thursday, 4 July 2013 at 13:55:17 UTC, TommiT wrote:What exactly in what I said there is flawed? Your example foo!int(arr) has nothing to do with what I said, because there's no type deduction in your example.DMD does the implicit conversion int[10] -> int[] while it is doing type deduction, which according to TDPL shouldn't happen.This is flawed since you can: int[10] arr; foo!int(arr).
Jul 04 2013
On Thursday, 4 July 2013 at 18:07:00 UTC, Maxim Fomin wrote:On Thursday, 4 July 2013 at 15:59:21 UTC, TommiT wrote:My implicit cast operator syntax is not redundant because it's not the same thing as your alias this example. My example would not and should not ever compile. The difference between alias this relationship and a mere implicit conversion operator is that alias this creates an is-a relationship, whereas implicit conversion operator does not. On Thursday, 4 July 2013 at 18:07:00 UTC, Maxim Fomin wrote:On Thursday, 4 July 2013 at 15:03:54 UTC, Maxim Fomin wrote:Your implicit syntax is redundant. What C++ does is irrelevant. D has alias this.[..] 2) In case of one parameter, a variable isn't tied to any type and usual implicit conversions are applied.Do you mean that if D had the C++ style implicit conversion operator (using let's say the keyword ' implicit'), then the following would compile? struct Wrap(T) { T t; } struct Toy { alias Wrapped = Wrap!Toy; implicit Wrapped opCast(T : Wrapped)() { return Wrapped.init; } } void foo(T)(Wrap!T) { } void main() { foo(Toy.init); }import std.stdio; struct Wrap(T) { T t; } struct Toy { alias get this; Wrap!Toy get() { return Wrap!Toy.init; } } void foo(T)(Wrap!T t) { writeln(T.stringof); } void main() { foo(Toy.init); } Note, that T is Toy, so there were no type conversion during template instantiation. There was argument conversion after instantiation, as it happens usually. Back to foo function accepting slice - dmd does the same thing.DMD doesn't do the same thing for static arrays. Due to alias this, your Toy is a Wrap!Toy for all intents and purposes. There's no is-a relationship between a static array type and the dynamic array type which it implicitly converts to. What happens when static array implicitly converts to dynamic array is the same type of implicit conversion which happens when long converts to double. There's no is-a relationship between long and double.Here's what the compiler does during type deduction when it sees the following function template and its instantiation: void foo(T)(T[] da) { } int[10] sa; foo(sa); Step 1: The compiler tries to figure out the type T such as the parameter da would have the same type as the argument sa which was passed to the function. The complier comes to the conclusion that there is not type which would make the type of da the same as the type of sa. For example, if T were int, then the type of da would be int[] which is not the same as the type of sa which is int[10]. Step 2: The compiler tries to see if the type of sa could be implicitly converted to something. The compiler realises that sa could be converted to an instance of type int[]. Then the compiler checks if this implicitly converted type could be passed to foo. The compiler figures out that if T is int, then the implicitly converted type int[] matches exactly with the type of the parameter da. Thus, the compiler declares that T must be int. Step 3: If the compiler hasn't managed to figure out what T is, it gives an error. If it has found out what T is, the compiler declares that the type deduction has been successfully accomplished. To answer your question "What implicit conversion did dmd do in the case of int[10] and int[]", see Step 2. At Step 2 the compiler does, or rather checks that it's possible to do, the implicit conversion from int[10] to int[]. That Step 2 right there is what no-one coming from C++ would expect to happen, and according to that quote from TDPL, that Step 2 should not happen in D.On Thursday, 4 July 2013 at 15:03:54 UTC, Maxim Fomin wrote:See above. What type implicit converision did dmd in case of int[10] and int[]. Conversion from int to int?On Thursday, 4 July 2013 at 13:55:17 UTC, TommiT wrote:So you admit that DMD does implicit conversion during type deduction?On Thursday, 4 July 2013 at 13:45:07 UTC, Maxim Fomin wrote:DMD is stupid, but not that. If it has T[] parameter, and int[10] static array which is convertible to int[] is passed, T is deduced to be int. What other types T can be? A float, object, or pointer to union?Actually if you pass integer static array, dmd deduces T to be int, [..]And that right there, "dmd deduces T to be int", is the crux of the matter. How on earth is DMD able to deduce T to be int, without using the implicit conversion from int[10] to int[] ?
Jul 04 2013
On Thursday, 4 July 2013 at 19:00:51 UTC, TommiT wrote:The idea that situation with alias this and arrays is functionally different is simply defeacted by static assert (is(int[1] : int[])); static assert (is(Toy : Wrap!Toy)); static assert (!is(int[1] == int[])); static assert (!is(Toy == Wrap!Toy));Note, that T is Toy, so there were no type conversion during template instantiation. There was argument conversion after instantiation, as it happens usually. Back to foo function accepting slice - dmd does the same thing.DMD doesn't do the same thing for static arrays. Due to alias this, your Toy is a Wrap!Toy for all intents and purposes. There's no is-a relationship between a static array type and the dynamic array type which it implicitly converts to. What happens when static array implicitly converts to dynamic array is the same type of implicit conversion which happens when long converts to double. There's no is-a relationship between long and double.This is nice and interesting to read. Please provide references to dmd code which support the description of dmd compiling process you provided (judging by how confident in this topic you are, you might have studied cast.c, expression.c and template.c wery well). Without such references any text pretending to tell something about what compiler does is cheap.See above. What type implicit converision did dmd in case of int[10] and int[]. Conversion from int to int?Here's what the compiler does during type deduction when it sees the following function template and its instantiation: void foo(T)(T[] da) { } int[10] sa; foo(sa); <steps follow ...>
Jul 04 2013
On Thursday, 4 July 2013 at 19:49:59 UTC, Maxim Fomin wrote:On Thursday, 4 July 2013 at 19:00:51 UTC, TommiT wrote:Is-a relationship between types means this type of thing: class Human { } class Baby : Human { } void main() { static assert(!is(Baby == Human)); } Baby is-a Human, but the type Baby is not same as Human. If static arrays used an alias this to convert to a dynamic array, then you'd able to append to a static array: struct DynamicArray(T) { void opOpAssign(string op : "+")(int n) { } } struct StaticArray(T, int size) { alias get this; DynamicArray!T get() property { return DynamicArray!T.init; } } void main() { StaticArray!(int, 4) sa; sa += 42; // Can't do this with static arrays } On Thursday, 4 July 2013 at 19:49:59 UTC, Maxim Fomin wrote:The idea that situation with alias this and arrays is functionally different is simply defeacted by static assert (is(int[1] : int[])); static assert (is(Toy : Wrap!Toy)); static assert (!is(int[1] == int[])); static assert (!is(Toy == Wrap!Toy));Note, that T is Toy, so there were no type conversion during template instantiation. There was argument conversion after instantiation, as it happens usually. Back to foo function accepting slice - dmd does the same thing.DMD doesn't do the same thing for static arrays. Due to alias this, your Toy is a Wrap!Toy for all intents and purposes. There's no is-a relationship between a static array type and the dynamic array type which it implicitly converts to. What happens when static array implicitly converts to dynamic array is the same type of implicit conversion which happens when long converts to double. There's no is-a relationship between long and double.On Thursday, 4 July 2013 at 19:00:51 UTC, TommiT wrote:I have never seen any DMD code. My deduction of how DMD _must_ work is based on: 1) my understanding of how template instantiation works in C++ 2) the fact that the call to foo(sa) does compile The compiler simply must know about implicit conversion of static to dynamic arrays during template instantiation, or otherwise it wouldn't be able to do the instantiation of foo for the call to foo(sa). And not only that, the compiler must accept a non-exact match between parameter and argument types. C++ never accepts anything but an exact match between the parameter types of the instantiated template function and the types of the arguments passed in to the function at the call site which caused the instantiation. That's pretty simple logic, which is why I'm confident that I'm right even though, like I said, I don't know anything about how DMD is written.This is nice and interesting to read. Please provide references to dmd code which support the description of dmd compiling process you provided (judging by how confident in this topic you are, you might have studied cast.c, expression.c and template.c wery well). Without such references any text pretending to tell something about what compiler does is cheap.See above. What type implicit converision did dmd in case of int[10] and int[]. Conversion from int to int?Here's what the compiler does during type deduction when it sees the following function template and its instantiation: void foo(T)(T[] da) { } int[10] sa; foo(sa); <steps follow ...>
Jul 04 2013
On Thursday, 4 July 2013 at 20:11:56 UTC, TommiT wrote:struct DynamicArray(T) { void opOpAssign(string op : "+")(int n) { } }That was supposed to be: struct DynamicArray(T) { void opOpAssign(string op : "~")(T value) { } }
Jul 04 2013
On Thursday, 4 July 2013 at 20:11:56 UTC, TommiT wrote:C++ never accepts anything but an exact match between the parameter types of the instantiated template function and the types of the arguments passed in to the function at the call site which caused the instantiation.Although, that's not exactly true. C++ accepts an inexact match when the instantiated parameter is either a reference or a pointer to a public base class of the passed argument type. I.e. there is an is-a relationship.
Jul 04 2013
On Thursday, 4 July 2013 at 20:11:56 UTC, TommiT wrote:I have never seen any DMD code. My deduction of how DMD _must_ work is based on: 1) my understanding of how template instantiation works in C++ 2) the fact that the call to foo(sa) does compileAnd this is a problem, because many of such naive judgemnets are actually false.The compiler simply must know about implicit conversion of static to dynamic arrays during template instantiation, or otherwise it wouldn't be able to do the instantiation of foo for the call to foo(sa).Implementation may do other way, at first instantiate template (with deduced type) and then try to plug arguments as in case of non-template function (including implicit conversion). If it cannot, implementation issues error message for a particular problem and then general "template error instantiation".And not only that, the compiler must accept a non-exact match between parameter and argument types. C++ never accepts anything but an exact match between the parameter types of the instantiated template function and the types of the arguments passed in to the function at the call site which caused the instantiation. That's pretty simple logic, which is why I'm confident that I'm right even though, like I said, I don't know anything about how DMD is written.D forums are not the right place to show confidence in C++ knowledge. What are your points regarding type deduction and implicit conversion in D?
Jul 04 2013
On Thursday, 4 July 2013 at 20:43:45 UTC, Maxim Fomin wrote:Implementation may do other way, at first instantiate template (with deduced type) and then try to plug arguments as in case of non-template function (including implicit conversion). If it cannot, implementation issues error message for a particular problem and then general "template error instantiation".Well, it doesn't really matter how it is implemented. What matters is that the implicit conversion does happen.What are your points regarding type deduction and implicit conversion in D?I thought my point would have been made painstakingly clear by now. My point is that D behaves in a way that's very different from C++ or any other language which does heterogeneous translation of type parameters. And I've never seen any mention of this neither in the spec nor in TDPL (nor have I seen this discussed before). This difference should be mentioned somewhere newcomers are guaranteed to see it.
Jul 04 2013
On Thursday, 4 July 2013 at 21:31:43 UTC, TommiT wrote:On Thursday, 4 July 2013 at 20:43:45 UTC, Maxim Fomin wrote:Issue in this case is not that it happens per se (of course, it does), but whether implicit conversion influences type deduction. As it was mentioned previously about particular example, it does not.Implementation may do other way, at first instantiate template (with deduced type) and then try to plug arguments as in case of non-template function (including implicit conversion). If it cannot, implementation issues error message for a particular problem and then general "template error instantiation".Well, it doesn't really matter how it is implemented. What matters is that the implicit conversion does happen.Please provide evidence which support your point about D. Previous example doesn't do that. Piece of dmd implementation is appreciated. Otherwise claims about what implementation does are of little value.What are your points regarding type deduction and implicit conversion in D?I thought my point would have been made painstakingly clear by now. My point is that D behaves in a way that's very different from C++ or any other language which does heterogeneous translation of type parameters. And I've never seen any mention of this neither in the spec nor in TDPL (nor have I seen this discussed before). This difference should be mentioned somewhere newcomers are guaranteed to see it.
Jul 04 2013
On Friday, 5 July 2013 at 02:45:47 UTC, Maxim Fomin wrote:On Thursday, 4 July 2013 at 21:31:43 UTC, TommiT wrote:Of course implicit conversion influences type deduction. If it didn't, if implicit conversion didn't have any say in type deduction, then the call foo(sa) would not compile. The compiler needs to know, and thus has to be influenced by the knowledge of implicit conversion, in order to be able to deduce T to be int. On Friday, 5 July 2013 at 02:45:47 UTC, Maxim Fomin wrote:On Thursday, 4 July 2013 at 20:43:45 UTC, Maxim Fomin wrote:Issue in this case is not that it happens per se (of course, it does), but whether implicit conversion influences type deduction. As it was mentioned previously about particular example, it does not.Implementation may do other way, at first instantiate template (with deduced type) and then try to plug arguments as in case of non-template function (including implicit conversion). If it cannot, implementation issues error message for a particular problem and then general "template error instantiation".Well, it doesn't really matter how it is implemented. What matters is that the implicit conversion does happen.The evidence of that D behaves differently from C++ is that foo(sa) compiles. I only talked about a possible implementation of it in DMD in order to explain this thing to you. But the actual implementation of it in DMD doesn't matter.Please provide evidence which support your point about D. Previous example doesn't do that. Piece of dmd implementation is appreciated. Otherwise claims about what implementation does are of little value.What are your points regarding type deduction and implicit conversion in D?I thought my point would have been made painstakingly clear by now. My point is that D behaves in a way that's very different from C++ or any other language which does heterogeneous translation of type parameters. And I've never seen any mention of this neither in the spec nor in TDPL (nor have I seen this discussed before). This difference should be mentioned somewhere newcomers are guaranteed to see it.
Jul 05 2013