digitalmars.D.learn - return type and templates
- Andrea Fontana (25/25) Nov 22 2013 I've seen many different topic about this, but they don't explain
- Jonathan M Davis (17/36) Nov 22 2013 And how would it know what type value should be instantiated with. It on...
- bearophile (6/10) Nov 22 2013 It could work if the type system become more powerful, but what
- Jonathan M Davis (11/20) Nov 22 2013 What's it going to do? Try ever type that it knows about and see which h...
- Andrea Fontana (10/38) Nov 22 2013 I just mean:
- Andrea Fontana (9/50) Nov 22 2013 Maybe it could be extended to function call if there's no
- Jonathan M Davis (26/39) Nov 22 2013 Again, how is the compiler supposed to have any clue that you want to
- Timon Gehr (11/52) Nov 22 2013 If you mean the type of the variable declaration, then yes it does.
- Jonathan M Davis (31/38) Nov 22 2013 How so? IFTI works by inferring the template arguments from the function...
- Andrea Fontana (4/67) Nov 22 2013 Timon was right, I mean T as return type.
- Timon Gehr (4/17) Nov 22 2013 I am not talking about the template constraint at all. The following
- Jonathan M Davis (9/39) Nov 22 2013 There are a few cases where the compiler does that but not many. In gene...
- Andrea Fontana (23/75) Nov 22 2013 I don't know how compiler works internally. (is there any
- Dicebot (7/10) Nov 22 2013 This is somewhat wrong part. "s.value" is distinct separate
- Timon Gehr (5/15) Nov 22 2013 Do you know the relevant compiler internals? I cannot really imagine it
- Jonathan M Davis (6/18) Nov 22 2013 I believe that the only cases where the compiler uses the left-hand side...
- Timon Gehr (2/20) Nov 22 2013 int delegate(int) dg = b?x=>x:x=>2*x;
- Jonathan M Davis (3/26) Nov 22 2013 Yeah. The result of the right-hand side is a lambda literal.
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (16/20) Nov 22 2013 of the
I've seen many different topic about this, but they don't explain what's wrong with this "proposed" feature. Who can explain me why this can't be added to language? Does it broke something? // Trivial example: struct Test { property auto value(T)() if (is(T == int)) { return _intValue; } property void value(T)(T val) if (is(T == int)) { _intValue = val; } private int _intValue; } void main() { Test s; s.value!int(3); // Works s.value(3); // Works, magic s.value = 3; // Works, magic int t1 = s.value!int; // Works auto t2 = s.value!int; // Works auto t4 = s.value; // Doesn't work (and i don't think it should) int t3 = s.value; // <--Doesn't work (can this feature be implemented?) }
Nov 22 2013
On Friday, November 22, 2013 10:24:38 Andrea Fontana wrote:I've seen many different topic about this, but they don't explain what's wrong with this "proposed" feature. Who can explain me why this can't be added to language? Does it broke something? // Trivial example: struct Test { property auto value(T)() if (is(T == int)) { return _intValue; } property void value(T)(T val) if (is(T == int)) { _intValue = val; } private int _intValue; }auto t4 = s.value; // Doesn't work (and i don't think it should) int t3 = s.value; // <--Doesn't work (can this feature be implemented?)And how would it know what type value should be instantiated with. It only knows in the case of s.value(7) because you gave it a value from which the compiler was able to infer the type. You didn't tell it anything in the case of s.value And it's not like the compiler can look at the template constraint and guess what will work or not - especially when template constraints can be arbitrarily complex. As far as the compiler is concerned, it's just a boolean expression which determines whether a given template instantiation is valid or not. At most, it's used for overloading when there are multiple templates which would otherwise match the given arguments. It's not going to work for the compiler to figure out what types might work with a given template constraint and then have it pick one when you don't tell the template what type to be instantiated with. - Jonathan M Davis
Nov 22 2013
Jonathan M Davis:It's not going to work for the compiler to figure out what types might work with a given template constraint and then have it pick one when you don't tell the template what type to be instantiated with.It could work if the type system become more powerful, but what are the costs in compiler complexity, compilation times, and possible bugs in user code? Bye, bearophile
Nov 22 2013
On Friday, November 22, 2013 11:24:30 bearophile wrote:Jonathan M Davis:What's it going to do? Try ever type that it knows about and see which happens to work? Try every type that it sees in the template constraint (particularly those in is expressions) and see if any of them work? It's a feature which sounds like you're trying to write AI. I don't think that even makes sense to attempt it. If there's really a type that makes sense by default, then just give a default template argument. Why try and make the compiler more complicated, particularly when it's questionable that it's a solvable problem, and it's pretty much a guarantee that it would have a high efficiency cost even if you could pull it off. - Jonathan M DavisIt's not going to work for the compiler to figure out what types might work with a given template constraint and then have it pick one when you don't tell the template what type to be instantiated with.It could work if the type system become more powerful, but what are the costs in compiler complexity, compilation times, and possible bugs in user code?
Nov 22 2013
On Friday, 22 November 2013 at 10:34:12 UTC, Jonathan M Davis wrote:On Friday, November 22, 2013 11:24:30 bearophile wrote:I just mean: int t = s.value; // Means int t = s.value!int; If there's a problem with template instantiatio is the same we have now. Now I have to write: int t = s.value!int; so if there's a problem with !int, it's just like now. It's just a syntactic sugar, no new feature... Am I wrong?Jonathan M Davis:What's it going to do? Try ever type that it knows about and see which happens to work? Try every type that it sees in the template constraint (particularly those in is expressions) and see if any of them work? It's a feature which sounds like you're trying to write AI. I don't think that even makes sense to attempt it. If there's really a type that makes sense by default, then just give a default template argument. Why try and make the compiler more complicated, particularly when it's questionable that it's a solvable problem, and it's pretty much a guarantee that it would have a high efficiency cost even if you could pull it off. - Jonathan M DavisIt's not going to work for the compiler to figure out what types might work with a given template constraint and then have it pick one when you don't tell the template what type to be instantiated with.It could work if the type system become more powerful, but what are the costs in compiler complexity, compilation times, and possible bugs in user code?
Nov 22 2013
On Friday, 22 November 2013 at 10:50:58 UTC, Andrea Fontana wrote:On Friday, 22 November 2013 at 10:34:12 UTC, Jonathan M Davis wrote:Maybe it could be extended to function call if there's no ambiguities. something like; void test(int a, long b); test(s.value, t.value); => test(s.value!int, t.value!long); just if test has no abiguities with overload or template params. In this case we can throw an exception and template param must be explicit.On Friday, November 22, 2013 11:24:30 bearophile wrote:I just mean: int t = s.value; // Means int t = s.value!int; If there's a problem with template instantiatio is the same we have now. Now I have to write: int t = s.value!int; so if there's a problem with !int, it's just like now. It's just a syntactic sugar, no new feature... Am I wrong?Jonathan M Davis:What's it going to do? Try ever type that it knows about and see which happens to work? Try every type that it sees in the template constraint (particularly those in is expressions) and see if any of them work? It's a feature which sounds like you're trying to write AI. I don't think that even makes sense to attempt it. If there's really a type that makes sense by default, then just give a default template argument. Why try and make the compiler more complicated, particularly when it's questionable that it's a solvable problem, and it's pretty much a guarantee that it would have a high efficiency cost even if you could pull it off. - Jonathan M DavisIt's not going to work for the compiler to figure out what types might work with a given template constraint and then have it pick one when you don't tell the template what type to be instantiated with.It could work if the type system become more powerful, but what are the costs in compiler complexity, compilation times, and possible bugs in user code?
Nov 22 2013
On Friday, November 22, 2013 11:50:57 Andrea Fontana wrote:I just mean: int t = s.value; // Means int t = s.value!int; If there's a problem with template instantiatio is the same we have now. Now I have to write: int t = s.value!int; so if there's a problem with !int, it's just like now. It's just a syntactic sugar, no new feature... Am I wrong?Again, how is the compiler supposed to have any clue that you want to instantiate value with int in the case of int t = s.value; The left-hand side of the expression has no impact on the type of the right- hand side, and you have not given the compiler any information as to what template argument should be given to value. s.value(3) only works because you've given value a function argument from which the corresponding template argument can be inforred. With s.value, you've given no indication whatsoever as to what value should be instantiated with. If you want a default template argument, then give it one. e.g. property auto value(T = int)() if (is(T == int)) { return _intValue; } But I don't know how you expect the compiler to have any clue what type value should be instantiated with when you haven't given it any template arguments and there are no function arguments to infer the template arguments from - especially when this what the compiler really sees template value(T) if(is(T == int)) { property auto value() { return _intValue; } } and it doesn't even look at the template constraint, let alone the contents of the template, until you attempt to instantiate the template. And it's not going to be able to try and instantiate the template without having any template arguments. - Jonathan M Davis
Nov 22 2013
On 11/22/2013 01:29 PM, Jonathan M Davis wrote:On Friday, November 22, 2013 11:50:57 Andrea Fontana wrote:If you mean the type of the variable declaration, then yes it does. int delegate(int) dg1 = x=>x; float delegate(float) dg2 = x=>x; static assert(!is(typeof(x=>x)));I just mean: int t = s.value; // Means int t = s.value!int; If there's a problem with template instantiatio is the same we have now. Now I have to write: int t = s.value!int; so if there's a problem with !int, it's just like now. It's just a syntactic sugar, no new feature... Am I wrong?Again, how is the compiler supposed to have any clue that you want to instantiate value with int in the case of int t = s.value; The left-hand side of the expression has no impact on the type of the right- hand side,and you have not given the compiler any information as to what template argument should be given to value.Well, technically, in this case there is only one choice.s.value(3) only works because you've given value a function argument from which the corresponding template argument can be inforred. With s.value, you've given no indication whatsoever as to what value should be instantiated with. If you want a default template argument, then give it one. e.g. property auto value(T = int)() if (is(T == int)) { return _intValue; } But I don't know how you expect the compiler to have any clue what type value should be instantiated with when you haven't given it any template arguments and there are no function arguments to infer the template arguments from - especially when this what the compiler really sees template value(T) if(is(T == int)) { property auto value() { return _intValue; } } and it doesn't even look at the template constraint, let alone the contents of the template, until you attempt to instantiate the template. And it's not going to be able to try and instantiate the template without having any template arguments. ...The request would be reasonable if 'value' was declared as follows though: property T value(T)() if (is(T == int)) { return _intValue; } i.e. the fact that the template argument equals the type of the resulting call can be read off directly from the signature. This is in the same ballpark as the existing IFTI features.
Nov 22 2013
On Friday, November 22, 2013 14:29:46 Timon Gehr wrote:The request would be reasonable if 'value' was declared as follows though: property T value(T)() if (is(T == int)) { return _intValue; } i.e. the fact that the template argument equals the type of the resulting call can be read off directly from the signature. This is in the same ballpark as the existing IFTI features.How so? IFTI works by inferring the template arguments from the function arguments. In this case, for the compiler to figure out a type that it could use to instantiate the template, it would have to disect the template constraint, which is compeletly different. Yes, this particular template constraint is very simplistic, but the compiler doesn't even look at the template constraint until it has a type to test with it, and in most cases, it would have no way of inferring what types might work even if it did look. Trying to get the compiler to infer T for value would be a drastic change to how it deals with templates, and at best, it would be able to figure out what to do in only the most simplistic of cases. In fact, the only cases that it could figure it out would very simplistic cases where there was only one possible answer, and if there's only one type that will work with a template, then there really wasn't much point in templatizing it in the first place. And as soon as there are multiple types which could work with a template, the compiler couldn't figure out the correct type no matter how smart it was, because it would need a way of choosing which of the options to take. e.g. template foo(T) if(is(T == int) || is(T == byte)) { ... } Should foo be instantiated with int or byte? Both are equally valid. The OP has come up with a contrived example where it seems obvious to him what type the compiler should use to instantiate a template which has been given no template arguments and no function arguments to infer the template arguments from. But the compiler has no plumbing for figuring out such a thing, and adding such plumbing would be pointless, because it would only work in contrived cases such as this one where there was no point in templatizing the function in the first place. - Jonathan M Davis
Nov 22 2013
On Friday, 22 November 2013 at 13:43:59 UTC, Jonathan M Davis wrote:On Friday, November 22, 2013 14:29:46 Timon Gehr wrote:Timon was right, I mean T as return type. Too bad it needs a drastic change :\The request would be reasonable if 'value' was declared as follows though: property T value(T)() if (is(T == int)) { return _intValue; } i.e. the fact that the template argument equals the type of the resulting call can be read off directly from the signature. This is in the same ballpark as the existing IFTI features.How so? IFTI works by inferring the template arguments from the function arguments. In this case, for the compiler to figure out a type that it could use to instantiate the template, it would have to disect the template constraint, which is compeletly different. Yes, this particular template constraint is very simplistic, but the compiler doesn't even look at the template constraint until it has a type to test with it, and in most cases, it would have no way of inferring what types might work even if it did look. Trying to get the compiler to infer T for value would be a drastic change to how it deals with templates, and at best, it would be able to figure out what to do in only the most simplistic of cases. In fact, the only cases that it could figure it out would very simplistic cases where there was only one possible answer, and if there's only one type that will work with a template, then there really wasn't much point in templatizing it in the first place. And as soon as there are multiple types which could work with a template, the compiler couldn't figure out the correct type no matter how smart it was, because it would need a way of choosing which of the options to take. e.g. template foo(T) if(is(T == int) || is(T == byte)) { ... } Should foo be instantiated with int or byte? Both are equally valid. The OP has come up with a contrived example where it seems obvious to him what type the compiler should use to instantiate a template which has been given no template arguments and no function arguments to infer the template arguments from. But the compiler has no plumbing for figuring out such a thing, and adding such plumbing would be pointless, because it would only work in contrived cases such as this one where there was no point in templatizing the function in the first place. - Jonathan M Davis
Nov 22 2013
On 11/22/2013 02:43 PM, Jonathan M Davis wrote:On Friday, November 22, 2013 14:29:46 Timon Gehr wrote:I am not talking about the template constraint at all. The following would still be a signature that would work: property T value(T)(){ return _intValue; }How so? IFTI works by inferring the template arguments from the function arguments. In this case, for the compiler to figure out a type that it could use to instantiate the template, it would have to disect the template constraint, which is compeletly different. Yes, this particular template constraint ...The request would be reasonable if 'value' was declared as follows though: property T value(T)() if (is(T == int)) { return _intValue; } i.e. the fact that the template argument equals the type of the resulting call can be read off directly from the signature. This is in the same ballpark as the existing IFTI features.
Nov 22 2013
On Friday, November 22, 2013 14:29:46 Timon Gehr wrote:On 11/22/2013 01:29 PM, Jonathan M Davis wrote:There are a few cases where the compiler does that but not many. In general, the right-hand side of an assignment is evaluated separately from the left and thus gets no type information from the left-hand side. But even if it did, in this case, that would mean determining the template argument from the return type, which is completely backwards to how template instantiation works, and attempting that would be a lot like attempting to overload on the return type of a function, which completely goes against how C-based languages work. - Jonathan M DavisOn Friday, November 22, 2013 11:50:57 Andrea Fontana wrote:If you mean the type of the variable declaration, then yes it does. int delegate(int) dg1 = x=>x; float delegate(float) dg2 = x=>x; static assert(!is(typeof(x=>x)));I just mean: int t = s.value; // Means int t = s.value!int; If there's a problem with template instantiatio is the same we have now. Now I have to write: int t = s.value!int; so if there's a problem with !int, it's just like now. It's just a syntactic sugar, no new feature... Am I wrong?Again, how is the compiler supposed to have any clue that you want to instantiate value with int in the case of int t = s.value; The left-hand side of the expression has no impact on the type of the right- hand side,
Nov 22 2013
On Friday, 22 November 2013 at 12:29:25 UTC, Jonathan M Davis wrote:On Friday, November 22, 2013 11:50:57 Andrea Fontana wrote:I don't know how compiler works internally. (is there any documentation other than the comments and code itself?) So probably I'm wrong about what compiler knows and not. Parsing this: int t = s.value; I assumed that it knows - when is trying to instatiate s.value template - that "s.value" is part of an assignment and that it will be assigned to an int. So if template argument is missed and s.value returns T, T should be int. But if I understand your answer, right-hand side can't see left-hand side. By the way the default value doesn't works for me because in my library I have to choose from many different template. So i have to do every time: int i = asd.value!int; string s = asd.value!string; long l = asd.value!long; and so on... and i hoped I could do: int i = asd.value; string s = asd.value; long l = asd.value; Ok, if it's impossible, never mind :)I just mean: int t = s.value; // Means int t = s.value!int; If there's a problem with template instantiatio is the same we have now. Now I have to write: int t = s.value!int; so if there's a problem with !int, it's just like now. It's just a syntactic sugar, no new feature... Am I wrong?Again, how is the compiler supposed to have any clue that you want to instantiate value with int in the case of int t = s.value; The left-hand side of the expression has no impact on the type of the right- hand side, and you have not given the compiler any information as to what template argument should be given to value. s.value(3) only works because you've given value a function argument from which the corresponding template argument can be inforred. With s.value, you've given no indication whatsoever as to what value should be instantiated with. If you want a default template argument, then give it one. e.g. property auto value(T = int)() if (is(T == int)) { return _intValue; } But I don't know how you expect the compiler to have any clue what type value should be instantiated with when you haven't given it any template arguments and there are no function arguments to infer the template arguments from - especially when this what the compiler really sees template value(T) if(is(T == int)) { property auto value() { return _intValue; } } and it doesn't even look at the template constraint, let alone the contents of the template, until you attempt to instantiate the template. And it's not going to be able to try and instantiate the template without having any template arguments. - Jonathan M Davis
Nov 22 2013
On Friday, 22 November 2013 at 13:43:49 UTC, Andrea Fontana wrote:I assumed that it knows - when is trying to instatiate s.value template - that "s.value" is part of an assignment and that it will be assigned to an int.This is somewhat wrong part. "s.value" is distinct separate expression that must be evaluated by compiler on its own before proceeding. The fact that it is later used in assignment expression is not know at that moment. One can define some analysis rules that will make it do so but it is a very major change to compiler internals.
Nov 22 2013
On 11/22/2013 02:50 PM, Dicebot wrote:On Friday, 22 November 2013 at 13:43:49 UTC, Andrea Fontana wrote:Lambda parameter type deduction needs to know this too.I assumed that it knows - when is trying to instatiate s.value template - that "s.value" is part of an assignment and that it will be assigned to an int.This is somewhat wrong part. "s.value" is distinct separate expression that must be evaluated by compiler on its own before proceeding. The fact that it is later used in assignment expression is not know at that moment.One can define some analysis rules that will make it do so but it is a very major change to compiler internals.Do you know the relevant compiler internals? I cannot really imagine it being a major change. (It wouldn't be in the D frontend I am currently developing as a side project.)
Nov 22 2013
On Friday, November 22, 2013 15:20:30 Timon Gehr wrote:On 11/22/2013 02:50 PM, Dicebot wrote:I believe that the only cases where the compiler uses the left-hand side of of an assignment or initialization to determine anything about the type of the right-hand side is when the right-hand side is a literal (be it a lambda literal, array literal, or some other kind of literal). - Jonathan M DavisOn Friday, 22 November 2013 at 13:43:49 UTC, Andrea Fontana wrote:Lambda parameter type deduction needs to know this too.I assumed that it knows - when is trying to instatiate s.value template - that "s.value" is part of an assignment and that it will be assigned to an int.This is somewhat wrong part. "s.value" is distinct separate expression that must be evaluated by compiler on its own before proceeding. The fact that it is later used in assignment expression is not know at that moment.
Nov 22 2013
On 11/22/2013 04:14 PM, Jonathan M Davis wrote:On Friday, November 22, 2013 15:20:30 Timon Gehr wrote:int delegate(int) dg = b?x=>x:x=>2*x;On 11/22/2013 02:50 PM, Dicebot wrote:I believe that the only cases where the compiler uses the left-hand side of of an assignment or initialization to determine anything about the type of the right-hand side is when the right-hand side is a literal (be it a lambda literal, array literal, or some other kind of literal). - Jonathan M DavisOn Friday, 22 November 2013 at 13:43:49 UTC, Andrea Fontana wrote:Lambda parameter type deduction needs to know this too.I assumed that it knows - when is trying to instatiate s.value template - that "s.value" is part of an assignment and that it will be assigned to an int.This is somewhat wrong part. "s.value" is distinct separate expression that must be evaluated by compiler on its own before proceeding. The fact that it is later used in assignment expression is not know at that moment.
Nov 22 2013
On Friday, November 22, 2013 16:21:43 Timon Gehr wrote:On 11/22/2013 04:14 PM, Jonathan M Davis wrote:Yeah. The result of the right-hand side is a lambda literal. - Jonathan M DavisOn Friday, November 22, 2013 15:20:30 Timon Gehr wrote:int delegate(int) dg = b?x=>x:x=>2*x;On 11/22/2013 02:50 PM, Dicebot wrote:I believe that the only cases where the compiler uses the left-hand side of of an assignment or initialization to determine anything about the type of the right-hand side is when the right-hand side is a literal (be it a lambda literal, array literal, or some other kind of literal). - Jonathan M DavisOn Friday, 22 November 2013 at 13:43:49 UTC, Andrea Fontana wrote:Lambda parameter type deduction needs to know this too.I assumed that it knows - when is trying to instatiate s.value template - that "s.value" is part of an assignment and that it will be assigned to an int.This is somewhat wrong part. "s.value" is distinct separate expression that must be evaluated by compiler on its own before proceeding. The fact that it is later used in assignment expression is not know at that moment.
Nov 22 2013
On 11/22/2013 07:14 AM, Jonathan M Davis wrote:I believe that the only cases where the compiler uses the left-handside of ofan assignment or initialization to determine anything about the typeof theright-hand side is when the right-hand side is a literal (be it a lambda literal, array literal, or some other kind of literal).Any implicit conversion needs that too, e.g. alias this. struct S { double d; alias d this; } void main() { auto s = S(); double d = s; } The example will be more impressive when multiple 'alias this' is supported. Ali
Nov 22 2013