www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Deduce template arguments from return value?

reply "Yuxuan Shui" <yshuiv7 gmail.com> writes:
For example:
import std.conv;
T a(T)(int a) {
	return to!T(a);
}
void main(){
	string x = a(2);
}

D is not able to deduce T. Can we make it possible to deduce 
template arguments from where the return value is assigned to?

Rust is able to do this:
fn main() {
	let a : Vec<i32> = Vec::new();
}

(In fact, you can even do this is Rust:
fn main() {
	let mut a = Vec::new();
	a[0] = 0i32;
})
Jul 12 2015
next sibling parent reply "rsw0x" <anonymous anonymous.com> writes:
On Sunday, 12 July 2015 at 09:13:03 UTC, Yuxuan Shui wrote:
 For example:
 import std.conv;
 T a(T)(int a) {
 	return to!T(a);
 }
 void main(){
 	string x = a(2);
 }

 D is not able to deduce T. Can we make it possible to deduce 
 template arguments from where the return value is assigned to?
auto a(T)(int a) { return to!T(a); } ?
Jul 12 2015
parent "Yuxuan Shui" <yshuiv7 gmail.com> writes:
On Sunday, 12 July 2015 at 10:45:52 UTC, rsw0x wrote:
 On Sunday, 12 July 2015 at 09:13:03 UTC, Yuxuan Shui wrote:
 For example:
 import std.conv;
 T a(T)(int a) {
 	return to!T(a);
 }
 void main(){
 	string x = a(2);
 }

 D is not able to deduce T. Can we make it possible to deduce 
 template arguments from where the return value is assigned to?
auto a(T)(int a) { return to!T(a); } ?
This doesn't seem to work in the example I gave.
Jul 12 2015
prev sibling parent reply "Idan Arye" <GenericNPC gmail.com> writes:
On Sunday, 12 July 2015 at 09:13:03 UTC, Yuxuan Shui wrote:
 For example:
 import std.conv;
 T a(T)(int a) {
 	return to!T(a);
 }
 void main(){
 	string x = a(2);
 }

 D is not able to deduce T. Can we make it possible to deduce 
 template arguments from where the return value is assigned to?

 Rust is able to do this:
 fn main() {
 	let a : Vec<i32> = Vec::new();
 }

 (In fact, you can even do this is Rust:
 fn main() {
 	let mut a = Vec::new();
 	a[0] = 0i32;
 })
Just like ML, Rust's amazing type inference comes with a price - a super strict type system. D has less strict type system, which allows - for example - implicit conversions in some cases(consider http://dpaste.dzfl.pl/ed83a75a48ba) For D to support Rust's kind of type inference, it's type system will need to be completely replaced with something much more strict. Whether you think such type systems are good or not - this change will result in a massive code breakage.
Jul 12 2015
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 07/12/2015 02:52 PM, Idan Arye wrote:
 On Sunday, 12 July 2015 at 09:13:03 UTC, Yuxuan Shui wrote:
 For example:
 import std.conv;
 T a(T)(int a) {
     return to!T(a);
 }
 void main(){
     string x = a(2);
 }

 D is not able to deduce T. Can we make it possible to deduce template
 arguments from where the return value is assigned to?

 Rust is able to do this:
 fn main() {
     let a : Vec<i32> = Vec::new();
 }

 (In fact, you can even do this is Rust:
 fn main() {
     let mut a = Vec::new();
     a[0] = 0i32;
 })
Just like ML, Rust's amazing type inference comes with a price - a super strict type system. D has less strict type system, which allows - for example - implicit conversions in some cases(consider http://dpaste.dzfl.pl/ed83a75a48ba) For D to support Rust's kind of type inference, it's type system will need to be completely replaced with something much more strict. Whether you think such type systems are good or not - this change will result in a massive code breakage.
Strictness is not really the main problem here. Even if your language supports implicit conversions/overloading, the language can just give you back an error in case of unresolvable ambiguity as in your example. The example given in the OP has as obvious correct answer `string`, even though `const(string)` would in principle be possible as well. It is more about the issue that D's type system is Turing complete, hence it is hard to come up with a very principled set of deduction rules. Maybe something like: "If the computation of the return type does not involve introspection on any unspecified template argument, template arguments can be deduced from the return type." Implementation is roughly: If an IFTI call has unresolved arguments, but there are restrictions on the return type, instantiate all remaining overloads of the template with wildcard arguments that resist any kind of introspection and analyze everything possible, ignoring template constraints and gagging any compilation errors. As soon as the return types for every overload have been determined in terms of the wildcards, unify them with what you know about the required return type and check the template constraints in an attempt to remove the remaining ambiguity. Error out if anything remains ambiguous.
Jul 12 2015
parent "Idan Arye" <GenericNPC gmail.com> writes:
On Sunday, 12 July 2015 at 14:13:22 UTC, Timon Gehr wrote:
 On 07/12/2015 02:52 PM, Idan Arye wrote:
 [...]
Strictness is not really the main problem here. Even if your language supports implicit conversions/overloading, the language can just give you back an error in case of unresolvable ambiguity as in your example. The example given in the OP has as obvious correct answer `string`, even though `const(string)` would in principle be possible as well. It is more about the issue that D's type system is Turing complete, hence it is hard to come up with a very principled set of deduction rules. Maybe something like: "If the computation of the return type does not involve introspection on any unspecified template argument, template arguments can be deduced from the return type." Implementation is roughly: If an IFTI call has unresolved arguments, but there are restrictions on the return type, instantiate all remaining overloads of the template with wildcard arguments that resist any kind of introspection and analyze everything possible, ignoring template constraints and gagging any compilation errors. As soon as the return types for every overload have been determined in terms of the wildcards, unify them with what you know about the required return type and check the template constraints in an attempt to remove the remaining ambiguity. Error out if anything remains ambiguous.
That's a good point, which raises quite a concern - if this type inference is used in a templated function, the function will work with simple template parameters(ones that the deduction system can handle) but not with complex ones(e.g. ones that use auto return type). This will make development of these templates harder, because you won't be able to test them with simple parameters...
Jul 12 2015