digitalmars.D - Eponymous template with static if
- Michael Galuza (30/30) Aug 09 2023 It's well known that template functions in D are just kind of
- Steven Schveighoffer (10/42) Aug 09 2023 In order for IFTI (Implicit Function Template Instantiation) to work,
- sighoya (5/20) Aug 09 2023 Giving it an explicit type make it workable
- Michael Galuza (26/27) Aug 10 2023 Of course, but such usage of a template functions is...
- Tejas (31/58) Aug 13 2023 D has [template
- Paul Backus (10/12) Aug 14 2023 You can use constraints with the `template` keyword. They attach
- sighoya (5/18) Aug 15 2023 Can you tell what `is(T)` is doing here?
- Timon Gehr (5/25) Aug 15 2023 Here it indeed serves no particular purpose, I think this was just to
- H. S. Teoh (18/30) Aug 15 2023 `is(T)` is standard idiom for checking whether T is a valid type.
- Nick Treleaven (3/16) Aug 15 2023 Those should be `is(typeof(data++))` and `is(typeof(data+0))`.
- sighoya (3/5) Aug 15 2023 Thanks.
- sighoya (4/10) Aug 15 2023 As template parameter types seem to be distinguishable by syntax
- Nick Treleaven (3/9) Aug 16 2023 See:
- Paul Backus (4/8) Aug 15 2023 It doesn't do anything. It's only there because I copied it from
- Michael Galuza (16/20) Aug 10 2023 Oh, I'm so stupid :-( `static if` restriction described in
- Steven Schveighoffer (6/29) Aug 10 2023 Oh nice! I wish I had known this was in there I would have just pointed
It's well known that template functions in D are just kind of eponymous template: ```d T square(T)(T t) { return t * t; } ``` is lowered to ```d template square(T) { T square(T t) { return t * t; } } ``` But if we write this: ```d template square(T) { static if (true) { T square(T t) { return t * t; } } } } ``` trivial expression `square(3)` won't compiled with message `Error: none of the overloads of template main.square are callable using argument types !()(int)`. Why? What I missed?
Aug 09 2023
On 8/9/23 12:55 PM, Michael Galuza wrote:It's well known that template functions in D are just kind of eponymous template: ```d T square(T)(T t) { return t * t; } ``` is lowered to ```d template square(T) { T square(T t) { return t * t; } } ``` But if we write this: ```d template square(T) { static if (true) { T square(T t) { return t * t; } } } } ``` trivial expression `square(3)` won't compiled with message `Error: none of the overloads of template main.square are callable using argument types !()(int)`. Why? What I missed?In order for IFTI (Implicit Function Template Instantiation) to work, template functions must be of a certain form. If I recall correctly, they must be immediate children of the template AST node. You can stuff other things in the template, but you can't do something like what you did. The fact that IFTI works at all is kind of a kludge. The compiler must match the argument types to the function call nested in the template to do pattern matching, and *then* instantiate the template. In other words, it has to look inside before instantiation. -Steve
Aug 09 2023
On Wednesday, 9 August 2023 at 16:55:04 UTC, Michael Galuza wrote:But if we write this: ```d template square(T) { static if (true) { T square(T t) { return t * t; } } } } ``` trivial expression `square(3)` won't compiled with message `Error: none of the overloads of template main.square are callable using argument types !()(int)`. Why? What I missed?Giving it an explicit type make it workable [example](https://run.dlang.io/?compiler=dmd&source=import%20std.stdio;%0A%0Atemplate%20square(T)%20%7B%0A%20%20%20%20static%20if%20(true)%20%7B%0A%20%20%20%20%20%20%20%20T%20square(T%20t)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20t%20*%20t;%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%0A%0Avoid%20main()%0A%7B%0A%20%20%20%20%2F%2F%20Let%27s%20get%20going!%0A%20%20%20square!(int)(3);%0A%20%20%20writeln(square!(int)(3));%0A%20%20%20%20%2F%2F%20%22Range%20algorithms%22%20page%20under%20%22Gems%22%0A%7D) It seems not providing a template argument make it default to void.
Aug 09 2023
On Wednesday, 9 August 2023 at 18:28:38 UTC, sighoya wrote:Giving it an explicit type make it workableOf course, but such usage of a template functions is... useless:-) I want type argument `T` will be inferred. Anyway, I wondered why compiler rewrite `square!(int)(3)` as `square!(int).square(3)`, but in the same time it's not so clever to eliminate `!(int)`. I can only guess that type inference is impossible in this situation. I mean in ordinary cases compiler can match literal `3` and type `int` directly, but what it should do in such simple case: ``` template square(T) { static if (is(T)) { T square(T t) { return t * t; } } } ``` Of course compiler could conclude that expression `square(3)` is correct only if `static if` branch was successful, so `is(T) == true && T == int` (hi, Hindley–Milner :-), but such type inference require complex analysis "bottom-up", from template members to template itself, whereas we analyse template body "up-down", from template args and static if-s to members. Of course all above is just my poor and miserable tryings to understand compiler's pranks, don't judge me.
Aug 10 2023
On Thursday, 10 August 2023 at 14:34:20 UTC, Michael Galuza wrote:On Wednesday, 9 August 2023 at 18:28:38 UTC, sighoya wrote:D has [template constraints](https://dlang.org/spec/template.html#template_constraints) that will do that for you(but I don't think it works when you explicitly use `template` keyword): ```d import std; T square(T)(T param)if(is(T == int)){ return param * param; } void main() { writeln(square(123)); } ``` And if you want to use templates explicitly, you can use template specialization: ```d import std; template square(T:int){ T square(T param){ return param * param; } } void main() { writeln(square(123)); } ``` And, as you mentioned already, getting the compiler to deduce the kind of types that are valid for a given template body is not possible right now.Giving it an explicit type make it workableOf course, but such usage of a template functions is... useless:-) I want type argument `T` will be inferred. Anyway, I wondered why compiler rewrite `square!(int)(3)` as `square!(int).square(3)`, but in the same time it's not so clever to eliminate `!(int)`. I can only guess that type inference is impossible in this situation. I mean in ordinary cases compiler can match literal `3` and type `int` directly, but what it should do in such simple case: ``` template square(T) { static if (is(T)) { T square(T t) { return t * t; } } } ``` Of course compiler could conclude that expression `square(3)` is correct only if `static if` branch was successful, so `is(T) == true && T == int` (hi, Hindley–Milner :-), but such type inference require complex analysis "bottom-up", from template members to template itself, whereas we analyse template body "up-down", from template args and static if-s to members. Of course all above is just my poor and miserable tryings to understand compiler's pranks, don't judge me.
Aug 13 2023
On Monday, 14 August 2023 at 03:18:17 UTC, Tejas wrote:D has [template constraints](https://dlang.org/spec/template.html#template_constraints) that will do that for you(but I don't think it works when you explicitly use `template` keyword):You can use constraints with the `template` keyword. They attach to the template itself, not the function: ```d template square(T) if (is(T)) // <-- right here { T square(T param) { return param*param; } } ```
Aug 14 2023
On Monday, 14 August 2023 at 14:49:06 UTC, Paul Backus wrote:On Monday, 14 August 2023 at 03:18:17 UTC, Tejas wrote:Can you tell what `is(T)` is doing here? From the docs it seems to require `T` to be existing. However, I don't know what this exactly means, as T anyway have to exist.D has [template constraints](https://dlang.org/spec/template.html#template_constraints) that will do that for you(but I don't think it works when you explicitly use `template` keyword):You can use constraints with the `template` keyword. They attach to the template itself, not the function: ```d template square(T) if (is(T)) // <-- right here { T square(T param) { return param*param; } } ```
Aug 15 2023
On 8/15/23 12:25, sighoya wrote:On Monday, 14 August 2023 at 14:49:06 UTC, Paul Backus wrote:Here it indeed serves no particular purpose, I think this was just to illustrate the syntax.On Monday, 14 August 2023 at 03:18:17 UTC, Tejas wrote:Can you tell what `is(T)` is doing here?D has [template constraints](https://dlang.org/spec/template.html#template_constraints) that will do that for you(but I don't think it works when you explicitly use `template` keyword):You can use constraints with the `template` keyword. They attach to the template itself, not the function: ```d template square(T) if (is(T)) // <-- right here { T square(T param) { return param*param; } } ```From the docs it seems to require `T` to be existing. However, I don't know what this exactly means, as T anyway have to exist.It checks whether `T` is a valid type. I think currently nobody knows what this means, but there is a reference implementation.
Aug 15 2023
On Tue, Aug 15, 2023 at 10:25:56AM +0000, sighoya via Digitalmars-d wrote:On Monday, 14 August 2023 at 14:49:06 UTC, Paul Backus wrote:[...]`is(T)` is standard idiom for checking whether T is a valid type. It's usually used with an expression to test whether some operation is valid on a type, e.g.: auto myTemplateFunc(T)(T data) if (is(data++)) // make sure ++ is valid on T { return data++; } auto myTemplateFunc(T)(T data) if (is(data+0)) // make sure + int is valid on T { return data + 123; } T -- English is useful because it is a mess. Since English is a mess, it maps well onto the problem space, which is also a mess, which we call reality. Similarly, Perl was designed to be a mess, though in the nicest of all possible ways. -- Larry Wall```d template square(T) if (is(T)) // <-- right here { T square(T param) { return param*param; } } ```Can you tell what `is(T)` is doing here? From the docs it seems to require `T` to be existing. However, I don't know what this exactly means, as T anyway have to exist.
Aug 15 2023
On Tuesday, 15 August 2023 at 10:54:52 UTC, H. S. Teoh wrote: `is(T)` is standard idiom for checking whether T is a validtype. It's usually used with an expression to test whether some operation is valid on a type, e.g.: auto myTemplateFunc(T)(T data) if (is(data++)) // make sure ++ is valid on T { return data++; } auto myTemplateFunc(T)(T data) if (is(data+0)) // make sure + int is valid on T { return data + 123; }Those should be `is(typeof(data++))` and `is(typeof(data+0))`.
Aug 15 2023
On Tuesday, 15 August 2023 at 10:54:52 UTC, H. S. Teoh wrote:`is(T)` is standard idiom for checking whether T is a valid type.Thanks. Though, is there any case where it wouldn't be a valid type?
Aug 15 2023
On Tuesday, 15 August 2023 at 21:24:34 UTC, sighoya wrote:On Tuesday, 15 August 2023 at 10:54:52 UTC, H. S. Teoh wrote:As template parameter types seem to be distinguishable by syntax in my eyes: https://dlang.org/spec/template.html#parameters`is(T)` is standard idiom for checking whether T is a valid type.Thanks. Though, is there any case where it wouldn't be a valid type?
Aug 15 2023
On Tuesday, 15 August 2023 at 21:24:34 UTC, sighoya wrote:On Tuesday, 15 August 2023 at 10:54:52 UTC, H. S. Teoh wrote:See: https://dlang.org/spec/expression.html#is-type`is(T)` is standard idiom for checking whether T is a valid type.Thanks. Though, is there any case where it wouldn't be a valid type?
Aug 16 2023
On Tuesday, 15 August 2023 at 10:25:56 UTC, sighoya wrote:Can you tell what `is(T)` is doing here? From the docs it seems to require `T` to be existing. However, I don't know what this exactly means, as T anyway have to exist.It doesn't do anything. It's only there because I copied it from Michael Galuza's post (where it also doesn't do anything): https://forum.dlang.org/post/qglavaqzfzzxjcrfufpw forum.dlang.org
Aug 15 2023
On Wednesday, 9 August 2023 at 16:55:04 UTC, Michael Galuza wrote:Why? What I missed?Oh, I'm so stupid :-( `static if` restriction described in [26.1.1.1.2](https://dlang.org/spec/template.html#ifti-restrictions):When the template parameters must be deduced, the eponymous members can't rely on a `static if` condition since the deduction relies on how the members are used:```d template foo(T) { static if (is(T)) // T is not yet known... void foo(T t) {} // T is deduced from the member usage } void main() { //foo(0); // Error: cannot deduce function from argument types foo!int(0); // Ok since no deduction necessary } ``` I bet that this paragraph was added immediately after my question.
Aug 10 2023
On 8/10/23 12:44 PM, Michael Galuza wrote:On Wednesday, 9 August 2023 at 16:55:04 UTC, Michael Galuza wrote:Oh nice! I wish I had known this was in there I would have just pointed at it.Why? What I missed?Oh, I'm so stupid :-( `static if` restriction described in [26.1.1.1.2](https://dlang.org/spec/template.html#ifti-restrictions):When the template parameters must be deduced, the eponymous members can't rely on a `static if` condition since the deduction relies on how the members are used:```d template foo(T) { static if (is(T)) // T is not yet known... void foo(T t) {} // T is deduced from the member usage } void main() { //foo(0); // Error: cannot deduce function from argument types foo!int(0); // Ok since no deduction necessary } ```I bet that this paragraph was added immediately after my question.The site is on github ;) https://github.com/dlang/dlang.org/commit/190da42b6d6fe0abc205fda66a1d0e4086c5cf5c -Steve
Aug 10 2023