digitalmars.D - new DIP40: Template parameter deduction for constructors
- Timothee Cour (15/15) May 12 2013 A proposed feature of C++14 is to introduce template parameter
- timotheecour (3/3) May 12 2013 The link:
- deadalnix (3/6) May 12 2013 Not the first time it is mentioned. Definitively a direction we
- Peter Alexander (33/36) May 13 2013 This DIP is lacking in detail.
- Timothee Cour (2/2) May 13 2013 Thanks for the feedback, I've clarified the deduction mechanism and
- Kenji Hara (25/27) May 13 2013 Currently conditional compilation would stop IFTI.
- timotheecour (4/28) May 14 2013 I think that should be consistent with the deduction mechanism
- Timon Gehr (2/34) May 14 2013
- Timothee Cour (5/10) May 14 2013 it said 'Find all matching class/struct types in scope', isn't that eno...
- deadalnix (4/21) May 14 2013 I think the best here is to specify that the rule is the same
- Timon Gehr (3/24) May 14 2013 There is no spec for the IFTI case. (i.e. what happens if the eponymous
- deadalnix (3/5) May 14 2013 I know, but solving one problem at a time usual lead to better
- Timon Gehr (39/64) May 14 2013 DMD's strategy is roughly: use the first eponymous declaration that can
- deadalnix (2/42) May 14 2013 That creative. But completely b0rken IMO
- Kenji Hara (4/76) May 14 2013 Current dmd behavior is definitely a bug. Could you please file it in
- Timon Gehr (2/6) May 14 2013 http://d.puremagic.com/issues/show_bug.cgi?id=10083
- Timothee Cour (14/23) May 16 2013 ok Hara Kenji just fixed the bug, see
- deadalnix (2/6) May 16 2013 It may not. It is, by definition.
- Timon Gehr (17/27) May 14 2013 Apparently. The point is that it is not always possible to determine all...
- Jacob Carlborg (4/19) May 13 2013 I definitely want this.
- Steven Schveighoffer (12/27) May 13 2013 Definitely need/want this.
A proposed feature of C++14 is to introduce template parameter deduction for constructors, see paper, mentioned here. The idea is to deduce template parameters when calling a constructor given the arguments given to the constructor, whenever possible. A compile error occurs when the deduction is ambiguous. The benefits would be: * make the code more DRY * make boilerplate of class instantiators unnecessary in most cases (they're all over phobos, eg: std.typecons.tuple, std.typecons.rebindable etc) * make D more consistent: it deduces template parameters for functions, so why not for constructors, when this is unambiguous? * it won't break any code. Note, just as for deduction of normal functions, it should work with 0 or more template parameters specified (ie the first k>=0 templates may be provided).
May 12 2013
The link: http://wiki.dlang.org/DIP40 The paper links mentioned in the abstract are given in this DIP.
May 12 2013
On Monday, 13 May 2013 at 02:39:22 UTC, timotheecour wrote:The link: http://wiki.dlang.org/DIP40 The paper links mentioned in the abstract are given in this DIP.Not the first time it is mentioned. Definitively a direction we want to take.
May 12 2013
On Monday, 13 May 2013 at 02:39:22 UTC, timotheecour wrote:The link: http://wiki.dlang.org/DIP40 The paper links mentioned in the abstract are given in this DIP.This DIP is lacking in detail. struct A(T1) if(!is(T1==float)) { this(T2)(T2 a, T1 b){} this()(T1 b){} this()(){} } struct A(T1) if(is(T1==float)) { this()(){} } auto a=A(1,1.0); //deduced to A!(double)(1,1.0) auto a=A(1.0); //deduced to A!(double)(1.0) auto a=A(); //error: T1 cannot be deduced. How does the compiler decide which templates to attempt to instantiate? Does it just ignore conditional compilation conditions? If so, what would it do with this? struct A(T) if (is(T==float) && is(T!=float)) { this()(T a) {} } If the conditions are ignored then it will match this uninstantiable template. If it doesn't ignore the conditions then how does it determine T ahead of time to evaluate the conditions? One possible solution could be to first ignore the conditions, match the constructor, then check that the condition is okay. This is an extension on how normal function type deduction works though, so whatever mechanisms you have in mind need to be part of the proposal.
May 13 2013
Thanks for the feedback, I've clarified the deduction mechanism and show how it falls back to normal function template deduction.
May 13 2013
Currently conditional compilation would stop IFTI. template foo(T) { static if (is(T == int)) void foo(T) {} } void main() { foo(1); // shouldn't work } Same as above, DIP40 should prevent following case. template foo(T) { struct foo { static if (is(T == int)) this(T) {} } } void main() { foo(1); // also should not work } Kenji Hara 2013/5/14 Timothee Cour <thelastmammoth gmail.com>Thanks for the feedback, I've clarified the deduction mechanism and show how it falls back to normal function template deduction.
May 13 2013
On Tuesday, 14 May 2013 at 03:20:59 UTC, Kenji Hara wrote:Currently conditional compilation would stop IFTI. template foo(T) { static if (is(T == int)) void foo(T) {} } void main() { foo(1); // shouldn't work } Same as above, DIP40 should prevent following case. template foo(T) { struct foo { static if (is(T == int)) this(T) {} } } void main() { foo(1); // also should not work } Kenji HaraI think that should be consistent with the deduction mechanism proposed in the DIP: foo is struct not in scope until template foo(T) is instantiated.
May 14 2013
On 05/14/2013 09:06 AM, timotheecour wrote:On Tuesday, 14 May 2013 at 03:20:59 UTC, Kenji Hara wrote:No it is not. The DIP states "find all constructors".Currently conditional compilation would stop IFTI. template foo(T) { static if (is(T == int)) void foo(T) {} } void main() { foo(1); // shouldn't work } Same as above, DIP40 should prevent following case. template foo(T) { struct foo { static if (is(T == int)) this(T) {} } } void main() { foo(1); // also should not work } Kenji HaraI think that should be consistent with the deduction mechanism proposed in the DIP:foo is struct not in scope until template foo(T) is instantiated.
May 14 2013
I think that should be consistent with the deduction mechanism proposedin the DIP: foo is struct not in scope until template foo(T) is instantiated.No it is not. The DIP states "find all constructors".it said 'Find all matching class/struct types in scope', isn't that enough or am I missing something? To clarify, I've added 3 out of scope structs named A in the example section to clarify that they won't be included in the overload set. see the ones marked '//not in scope'
May 14 2013
On Tuesday, 14 May 2013 at 07:28:57 UTC, Timothee Cour wrote:I think the best here is to specify that the rule is the same than eponymous funtion and IFTY. Otherwise we'll have 2 different specs with small difference here and there. And that sucks.I think that should be consistent with the deduction mechanism proposedin the DIP: foo is struct not in scope until template foo(T) is instantiated.No it is not. The DIP states "find all constructors".it said 'Find all matching class/struct types in scope', isn't that enough or am I missing something? To clarify, I've added 3 out of scope structs named A in the example section to clarify that they won't be included in the overload set. see the ones marked '//not in scope'
May 14 2013
On 05/14/2013 10:04 AM, deadalnix wrote:On Tuesday, 14 May 2013 at 07:28:57 UTC, Timothee Cour wrote:There is no spec for the IFTI case. (i.e. what happens if the eponymous declaration inside the template is an overload set?)I think the best here is to specify that the rule is the same than eponymous funtion and IFTY. Otherwise we'll have 2 different specs with small difference here and there. And that sucks.I think that should be consistent with the deduction mechanism proposedin the DIP: foo is struct not in scope until template foo(T) is instantiated.No it is not. The DIP states "find all constructors".it said 'Find all matching class/struct types in scope', isn't that enough or am I missing something? To clarify, I've added 3 out of scope structs named A in the example section to clarify that they won't be included in the overload set. see the ones marked '//not in scope'
May 14 2013
On Tuesday, 14 May 2013 at 09:30:01 UTC, Timon Gehr wrote:There is no spec for the IFTI case. (i.e. what happens if the eponymous declaration inside the template is an overload set?)I know, but solving one problem at a time usual lead to better result than all at once.
May 14 2013
On 05/14/2013 11:30 AM, Timon Gehr wrote:On 05/14/2013 10:04 AM, deadalnix wrote:DMD's strategy is roughly: use the first eponymous declaration that can be found without analysing the template body for IFTI, then use the first eponymous declaration in the analyzed template body to resolve the eponymous declaration after instantiation. --- import std.stdio; template fun(T){ int fun(double arg){ return 1; } int fun(T arg){ return 0; } } void main(){ writeln(fun(2)); } // error --- import std.stdio; template fun(T){ int fun(T arg){ return 0; } int fun(double arg){ return 1; } } void main(){ writeln(fun(2)); } // ok --- This has funny implications, as the compiler may decide to resolve to a different declaration than was used for IFTI later, without doing any kind of overload resolution within the template body. --- template fun(T){ int fun(T arg){ return 0; } static if(true) int fun(double arg){ return 1; } } pragma(msg, fun(2)); // 0 --- template fun(T){ static if(true) int fun(double arg){ return 1; } int fun(T arg){ return 0; } } pragma(msg, fun(2)); // 1 --- In the second case, instantiation is performed with the second function, so T is resolved to 'int', but in the end, the 'double' overload is called with an implicit conversion.On Tuesday, 14 May 2013 at 07:28:57 UTC, Timothee Cour wrote:There is no spec for the IFTI case. (i.e. what happens if the eponymous declaration inside the template is an overload set?)I think the best here is to specify that the rule is the same than eponymous funtion and IFTY. Otherwise we'll have 2 different specs with small difference here and there. And that sucks.I think that should be consistent with the deduction mechanism proposedin the DIP: foo is struct not in scope until template foo(T) is instantiated.No it is not. The DIP states "find all constructors".it said 'Find all matching class/struct types in scope', isn't that enough or am I missing something? To clarify, I've added 3 out of scope structs named A in the example section to clarify that they won't be included in the overload set. see the ones marked '//not in scope'
May 14 2013
On Tuesday, 14 May 2013 at 09:56:14 UTC, Timon Gehr wrote:DMD's strategy is roughly: use the first eponymous declaration that can be found without analysing the template body for IFTI, then use the first eponymous declaration in the analyzed template body to resolve the eponymous declaration after instantiation. --- import std.stdio; template fun(T){ int fun(double arg){ return 1; } int fun(T arg){ return 0; } } void main(){ writeln(fun(2)); } // error --- import std.stdio; template fun(T){ int fun(T arg){ return 0; } int fun(double arg){ return 1; } } void main(){ writeln(fun(2)); } // ok --- This has funny implications, as the compiler may decide to resolve to a different declaration than was used for IFTI later, without doing any kind of overload resolution within the template body. --- template fun(T){ int fun(T arg){ return 0; } static if(true) int fun(double arg){ return 1; } } pragma(msg, fun(2)); // 0 --- template fun(T){ static if(true) int fun(double arg){ return 1; } int fun(T arg){ return 0; } } pragma(msg, fun(2)); // 1 --- In the second case, instantiation is performed with the second function, so T is resolved to 'int', but in the end, the 'double' overload is called with an implicit conversion.That creative. But completely b0rken IMO
May 14 2013
2013/5/14 Timon Gehr <timon.gehr gmx.ch>On 05/14/2013 11:30 AM, Timon Gehr wrote:Current dmd behavior is definitely a bug. Could you please file it in bugzilla? Kenji HaraOn 05/14/2013 10:04 AM, deadalnix wrote:DMD's strategy is roughly: use the first eponymous declaration that can be found without analysing the template body for IFTI, then use the first eponymous declaration in the analyzed template body to resolve the eponymous declaration after instantiation. --- import std.stdio; template fun(T){ int fun(double arg){ return 1; } int fun(T arg){ return 0; } } void main(){ writeln(fun(2)); } // error --- import std.stdio; template fun(T){ int fun(T arg){ return 0; } int fun(double arg){ return 1; } } void main(){ writeln(fun(2)); } // ok --- This has funny implications, as the compiler may decide to resolve to a different declaration than was used for IFTI later, without doing any kind of overload resolution within the template body. --- template fun(T){ int fun(T arg){ return 0; } static if(true) int fun(double arg){ return 1; } } pragma(msg, fun(2)); // 0 --- template fun(T){ static if(true) int fun(double arg){ return 1; } int fun(T arg){ return 0; } } pragma(msg, fun(2)); // 1 --- In the second case, instantiation is performed with the second function, so T is resolved to 'int', but in the end, the 'double' overload is called with an implicit conversion.On Tuesday, 14 May 2013 at 07:28:57 UTC, Timothee Cour wrote:There is no spec for the IFTI case. (i.e. what happens if the eponymous declaration inside the template is an overload set?)I think the best here is to specify that the rule is the same than eponymous funtion and IFTY. Otherwise we'll have 2 different specs with small difference here and there. And that sucks.I think that should be consistent with the deduction mechanism proposedNo it is not. The DIP states "find all constructors".in the DIP: foo is struct not in scope until template foo(T) is instantiated.it said 'Find all matching class/struct types in scope', isn't that enough or am I missing something? To clarify, I've added 3 out of scope structs named A in the example section to clarify that they won't be included in the overload set. see the ones marked '//not in scope'
May 14 2013
On 05/14/2013 05:08 PM, Kenji Hara wrote:... Current dmd behavior is definitely a bug. Could you please file it in bugzilla? ...http://d.puremagic.com/issues/show_bug.cgi?id=10083
May 14 2013
ok Hara Kenji just fixed the bug, see https://github.com/D-Programming-Language/dmd/pull/2041 So what's left unspecified now wrt DIP40? My proposal was to just address case C2 below, not C1 (at least initially): case C1: template A(T1) {struct A{ this()(T1 a) {} }} case C2: struct A(T1){ this()(T1 a) {}} Even though struct A(T1) may internally be implemented as template A(T1), I think the most useful / less problematic conversion is just case C2. In other words, as i said before, the constructors inside a template (as in case C1) would note be considered as part of the overload set for this DIP40 (at least initially). On Tue, May 14, 2013 at 12:02 PM, Timon Gehr <timon.gehr gmx.ch> wrote:On 05/14/2013 05:08 PM, Kenji Hara wrote:... Current dmd behavior is definitely a bug. Could you please file it in bugzilla? ...http://d.puremagic.com/issues/**show_bug.cgi?id=10083<http://d.puremagic.com/issues/show_bug.cgi?id=10083>
May 16 2013
On Thursday, 16 May 2013 at 09:12:53 UTC, Timothee Cour wrote:Even though struct A(T1) may internally be implemented as template A(T1), I think the most useful / less problematic conversion is just case C2.It may not. It is, by definition.
May 16 2013
On 05/14/2013 09:28 AM, Timothee Cour wrote:I think that should be consistent with the deduction mechanism proposed in the DIP: foo is struct not in scope until template foo(T) is instantiated. No it is not. The DIP states "find all constructors". it said 'Find all matching class/struct types in scope', isn't that enough or am I missing something?Apparently. The point is that it is not always possible to determine all constructors before the template is instantiated. The DIP must state when and how it works and what happens if it does not.To clarify, I've added 3 out of scope structs named A in the example section to clarify that they won't be included in the overload set. see the ones marked '//not in scope'I don't get this. (Also, why is it relevant to the discussion?) The following declaration: template A(T1){ struct A{ //not in scope unless T1 is explicitly instantiated this()(T1 a) {} } } Is the same declaration, modulo constraint, as the preceding struct A(T1) if (!isNumeric!T1) { this()(T1 a) {} }
May 14 2013
On 2013-05-13 04:37, Timothee Cour wrote:A proposed feature of C++14 is to introduce template parameter deduction for constructors, see paper, mentioned here. The idea is to deduce template parameters when calling a constructor given the arguments given to the constructor, whenever possible. A compile error occurs when the deduction is ambiguous. The benefits would be: * make the code more DRY * make boilerplate of class instantiators unnecessary in most cases (they're all over phobos, eg: std.typecons.tuple, std.typecons.rebindable etc) * make D more consistent: it deduces template parameters for functions, so why not for constructors, when this is unambiguous? * it won't break any code. Note, just as for deduction of normal functions, it should work with 0 or more template parameters specified (ie the first k>=0 templates may be provided).I definitely want this. -- /Jacob Carlborg
May 13 2013
On Sun, 12 May 2013 22:37:43 -0400, Timothee Cour <thelastmammoth gmail.com> wrote:A proposed feature of C++14 is to introduce template parameter deduction for constructors, see paper, mentioned here. The idea is to deduce template parameters when calling a constructor given the arguments given to the constructor, whenever possible. A compile error occurs when the deduction is ambiguous. The benefits would be: * make the code more DRY * make boilerplate of class instantiators unnecessary in most cases (they're all over phobos, eg: std.typecons.tuple, std.typecons.rebindable etc) * make D more consistent: it deduces template parameters for functions, so why not for constructors, when this is unambiguous? * it won't break any code. Note, just as for deduction of normal functions, it should work with 0 or more template parameters specified (ie the first k>=0 templates may be provided).Definitely need/want this. I say it is most definitely possible given how IFTI works (it must partially instantiate the template). It should be noted that conditional compilation can stop this from working. As a first step, it should have exactly the same rules as IFTI, assuming the constructor is the eponymous IFTI function. BTW, related issue: http://d.puremagic.com/issues/show_bug.cgi?id=6082 with 4 votes so far Added a link there. -Steve
May 13 2013