digitalmars.D - Template Instantiation Bug
- Jonathan Marler (32/32) Nov 04 2014 In the past I don't get much response when I file a bug in
- Steven Schveighoffer (20/52) Nov 04 2014 This is as designed.
- Jonathan Marler (25/40) Nov 04 2014 Ah I see now. After reading your comment I had to walk through
- Walter Bright (7/10) Nov 04 2014 To answer a question not asked, why doesn't the compiler see the simple ...
- Jonathan Marler (36/48) Nov 04 2014 Yes, trying to reverse the logic inside a template in the GENERAL
- Jonathan Marler (14/26) Nov 05 2014 Actually I just realized that this would be IMPOSSIBLE in the
- Steven Schveighoffer (18/30) Nov 06 2014 The real problem is that D singles out specialized type construction for...
- Daniel Murphy (3/7) Nov 04 2014 https://issues.dlang.org/show_bug.cgi?id=1807
- Steven Schveighoffer (4/11) Nov 04 2014 Hm.. interesting to note that Martin's suggestion has come to fruition,
- Daniel Murphy (5/8) Nov 06 2014 Not really, templated aliases behave exactly the same as aliases in
In the past I don't get much response when I file a bug in BugZilla so I wanted to see if anyone could tell me anything about this issue in the forums. I believe a bug has already been created here: https://issues.dlang.org/show_bug.cgi?id=2372 Here's the code to reproduce it: -------------------------------------- import std.stdio; template Transform(T) { alias Transform = T; } void testTransform(T)(Transform!T t) { } void testNoTransform(T)(T t) { } void main(string[] args) { testTransform(3); // FAILS "cannot deduce function..." testTransform!int(3); testNoTransform(3); testNoTransform!int(3); } -------------------------------------- The test(3) line fails with this error message: main.d(15): Error: template main.testTransform cannot deduce function from argument types !()(int), candidates are: main.d(7): main.testTransform(T)(Transform!T t) Does anyone know anything about this, maybe this is "as designed"? Thanks in advance for the info.
Nov 04 2014
On 11/4/14 11:01 AM, Jonathan Marler wrote:In the past I don't get much response when I file a bug in BugZilla so I wanted to see if anyone could tell me anything about this issue in the forums. I believe a bug has already been created here: https://issues.dlang.org/show_bug.cgi?id=2372 Here's the code to reproduce it: -------------------------------------- import std.stdio; template Transform(T) { alias Transform = T; } void testTransform(T)(Transform!T t) { } void testNoTransform(T)(T t) { } void main(string[] args) { testTransform(3); // FAILS "cannot deduce function..." testTransform!int(3); testNoTransform(3); testNoTransform!int(3); } -------------------------------------- The test(3) line fails with this error message: main.d(15): Error: template main.testTransform cannot deduce function from argument types !()(int), candidates are: main.d(7): main.testTransform(T)(Transform!T t) Does anyone know anything about this, maybe this is "as designed"? Thanks in advance for the info.This is as designed. The reason is because the compiler cannot deduce *backwards* how to instantiate a template to get the right result. I ran into this a long time ago when porting Tango. Here is the counter-case: template Transform(T) { static if(is(T == string)) alias Transform = int; else static if(is(T == int)) alias Transform = string; else alias Transform = T; } Basically, the compiler has to figure out how to instantiate Transform in order for it to result in an int. While it's easy for us to see what it needs to do, it doesn't have that capability. People have argued in the past that anything with a simple alias should be doable. I don't know if that's true or not, but I don't think it works today. There may be a bug report somewhere on it, I didn't search. The bug you found is not it. -Steve
Nov 04 2014
On Tuesday, 4 November 2014 at 16:55:10 UTC, Steven Schveighoffer wrote:This is as designed. The reason is because the compiler cannot deduce *backwards* how to instantiate a template to get the right result. I ran into this a long time ago when porting Tango. Here is the counter-case: template Transform(T) { static if(is(T == string)) alias Transform = int; else static if(is(T == int)) alias Transform = string; else alias Transform = T; } Basically, the compiler has to figure out how to instantiate Transform in order for it to result in an int. While it's easy for us to see what it needs to do, it doesn't have that capability.Ah I see now. After reading your comment I had to walk through how the compiler works out the types but after doing so it makes sense. I've included my thoughts to aid any others with the same question. Given a template signature like this: void mytemplate(T)(T t) Whenever a call to the template does not specify the template parameter T, the compiler needs to be able to "deduce" the type of T. In the example given above, T is equal to the type of the first argument "typeof(t)". If you were to apply some type of transformation to the argument, then the compiler cannot deduce T because it cannot reverse the transformation. For example, if you had the following type transformation: template Transform(T) { alias Transform = T; } The compiler does not know how to "reverse" this template, meaning, given the output of Transform, the compiler cannot deduce what the input of Transform was EVEN IF THE TEMPLATE IS AS SIMPLE AS THIS ONE. I hope this helps for anybody else with the same question.
Nov 04 2014
On 11/4/2014 9:51 AM, Jonathan Marler wrote:given the output of Transform, the compiler cannot deduce what the input of Transform was EVEN IF THE TEMPLATE IS AS SIMPLE AS THIS ONE.To answer a question not asked, why doesn't the compiler see the simple case and handle it? The problem is that this becomes a special case in the language specification, making the language harder to understand. Cue bug reports of people confused about why the simpler cases work and the more complex ones do not, and they overall get a negative impression of the language. And I don't blame them.
Nov 04 2014
On Tuesday, 4 November 2014 at 21:48:29 UTC, Walter Bright wrote:On 11/4/2014 9:51 AM, Jonathan Marler wrote:Yes, trying to reverse the logic inside a template in the GENERAL case would likely be next to impossible, or at least, require alot of work/code to support something thay may not be very useful. And if you can't solve the general case, I agree you shouldn't support the simple cases. However, I'll bring up the reason I wanted this functionality in case you have another solution. I wanted to create a template that used different parameter attributes depending on the type. For example, I just submitted a pull request to phobos to optimize the put/doPut functions in std.range (https://github.com/D-Programming-Language/phobos/pull/2655) to only use ref OutputRange when necessary. For types like pointers, classes, delegates, and functions, the ref attribute is unnecessary and can inhibit compiler optimization. For my pull request, the only solution I could come up with was to have 2 instances of each function with a template guard that handles ref and non-ref paramters: private template isPassByValue(T) { enum bool isPassByValue = isPointer!T || is( T == class ) || is( T == delegate ) || is( T == function ) ; } void put(R, E)(R r, E e) if( isPassByValue!R ) { // put code } void put(R, E)(ref R r, E e) if( !isPassByValue!R ) { // exact same put code } There's got to be a better way to do this. If anyone has any ideas let me know.given the output of Transform, the compiler cannot deduce what the input of Transform was EVEN IF THE TEMPLATE IS AS SIMPLE AS THIS ONE.To answer a question not asked, why doesn't the compiler see the simple case and handle it? The problem is that this becomes a special case in the language specification, making the language harder to understand. Cue bug reports of people confused about why the simpler cases work and the more complex ones do not, and they overall get a negative impression of the language. And I don't blame them.
Nov 04 2014
On Tuesday, 4 November 2014 at 21:48:29 UTC, Walter Bright wrote:On 11/4/2014 9:51 AM, Jonathan Marler wrote:Actually I just realized that this would be IMPOSSIBLE in the general case since a template transormation isn't necessarily a 1-1 mapping. Consider, template Normalize(T) { static if(isIntegral!T) { alias Normalize = int; } else { alias Normalize = string; } } Given the output of Normalize, say int, there's no way of knowing if T was ubyte, long, int or whatever.given the output of Transform, the compiler cannot deduce what the input of Transform was EVEN IF THE TEMPLATE IS AS SIMPLE AS THIS ONE.To answer a question not asked, why doesn't the compiler see the simple case and handle it? The problem is that this becomes a special case in the language specification, making the language harder to understand. Cue bug reports of people confused about why the simpler cases work and the more complex ones do not, and they overall get a negative impression of the language. And I don't blame them.
Nov 05 2014
On 11/4/14 4:48 PM, Walter Bright wrote:On 11/4/2014 9:51 AM, Jonathan Marler wrote:The real problem is that D singles out specialized type construction for inference of types. For example: void foo(T)(const(T)*) This works, because D singles out type construction of an array as one that it can infer. However, try to apply this to a custom type: void foo(T)(Rebindable!(const(T))) This *doesn't* work. I wish it would, but I can understand the opposition to it. The issue is that D has gone down the path of using templates for type construction instead of adding language features, and this is one of the main drawbacks. I continue to think we should be providing mechanisms to hook IFTI. There are several cases where things that "just work" with builtins cannot be extended to custom types. -Stevegiven the output of Transform, the compiler cannot deduce what the input of Transform was EVEN IF THE TEMPLATE IS AS SIMPLE AS THIS ONE.To answer a question not asked, why doesn't the compiler see the simple case and handle it? The problem is that this becomes a special case in the language specification, making the language harder to understand. Cue bug reports of people confused about why the simpler cases work and the more complex ones do not, and they overall get a negative impression of the language. And I don't blame them.
Nov 06 2014
"Steven Schveighoffer" wrote in message news:m3b0dd$6e0$1 digitalmars.com...People have argued in the past that anything with a simple alias should be doable. I don't know if that's true or not, but I don't think it works today. There may be a bug report somewhere on it, I didn't search. The bug you found is not it.https://issues.dlang.org/show_bug.cgi?id=1807
Nov 04 2014
On 11/4/14 1:05 PM, Daniel Murphy wrote:"Steven Schveighoffer" wrote in message news:m3b0dd$6e0$1 digitalmars.com...Hm.. interesting to note that Martin's suggestion has come to fruition, might this be revisited? -StevePeople have argued in the past that anything with a simple alias should be doable. I don't know if that's true or not, but I don't think it works today. There may be a bug report somewhere on it, I didn't search. The bug you found is not it.https://issues.dlang.org/show_bug.cgi?id=1807
Nov 04 2014
"Steven Schveighoffer" wrote in message news:m3bap5$khl$1 digitalmars.com...Not really, templated aliases behave exactly the same as aliases in templates. The difference is purely syntax. I don't think it would be a good idea to add different semantics for them.https://issues.dlang.org/show_bug.cgi?id=1807Hm.. interesting to note that Martin's suggestion has come to fruition, might this be revisited?
Nov 06 2014