www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - template auto value

reply Jonathan Marler <johnnymarler gmail.com> writes:
I believe I found small hole in template parameter semantics.  
I've summarized it here 
(https://github.com/marler8997/dlangfeatures#template-auto-value-parameter). 
Wanted to get feedback before I look into creating a PR for it.

----------------------------------
COPY/PASTED from 
https://github.com/marler8997/dlangfeatures#template-auto-value-parameter
----------------------------------
If you reference the D grammar for templates (See 
https://dlang.org/spec/template.html), there are currently 5 
categories of template parameters:

TemplateParameter:
     TemplateTypeParameter
     TemplateValueParameter
     TemplateAliasParameter
     TemplateSequenceParameter
     TemplateThisParameter
However there is a hole in this list, namely, generic template 
value parameters. The current TemplateValueParameter grammar node 
must explicitly declare a "BasicType":

TemplateValueParameter:
     BasicType Declarator
     BasicType Declarator TemplateValueParameterSpecialization
     BasicType Declarator TemplateValueParameterDefault
     BasicType Declarator TemplateValueParameterSpecialization 
TemplateValueParameterDefault
For example:
---
template foo(string value)
{
}
foo!"hello";
---

However, you can't create a template that accepts a value of any 
type. This would a good use case for the auto keyword, i.e.
---
template foo(auto value)
{
}
foo!0;
foo!"hello";
---

This would be a simple change to the grammar, namely,

BasicTemplateType:
     BasicType
     auto

TemplateValueParameter:
     BasicTemplateType Declarator
     BasicTemplateType Declarator 
TemplateValueParameterSpecialization
     BasicTemplateType Declarator TemplateValueParameterDefault
     BasicTemplateType Declarator 
TemplateValueParameterSpecialization TemplateValueParameterDefault
Mar 02 2018
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Mar 02, 2018 at 11:51:08PM +0000, Jonathan Marler via Digitalmars-d
wrote:
 I believe I found small hole in template parameter semantics.
 [...] you can't create a template that accepts a value of any type.
Not true: template counterexample(alias T) {} int x; string s; alias U = counterexample!x; // OK alias V = counterexample!1; // OK alias W = counterexample!"yup"; // OK alias X = counterexample!s; // OK alias Z = counterexample!int; // NG The last one fails because a value is expected, not a type. If you *really* want to accept both values and types, `...` comes to the rescue: template rescue(T...) if (T.length == 1) {} int x; string s; alias U = rescue!x; // OK alias V = rescue!1; // OK alias W = rescue!"yup"; // OK alias X = rescue!s; // OK alias Z = rescue!int; // OK! T -- In a world without fences, who needs Windows and Gates? -- Christian Surchi
Mar 02 2018
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 03.03.2018 01:20, H. S. Teoh wrote:
 On Fri, Mar 02, 2018 at 11:51:08PM +0000, Jonathan Marler via Digitalmars-d
wrote:
 I believe I found small hole in template parameter semantics.
 [...] you can't create a template that accepts a value of any type.
Not true: template counterexample(alias T) {} int x; string s; alias U = counterexample!x; // OK alias V = counterexample!1; // OK alias W = counterexample!"yup"; // OK alias X = counterexample!s; // OK alias Z = counterexample!int; // NG The last one fails because a value is expected, not a type.
No, it fails because a "symbol" is expected, not a basic type. There really is no good reason why int should not be accepted -- a class or struct type would be accepted. IIRC Walter has agreed to this, and it's just pending implementation.
Mar 02 2018
prev sibling parent reply Jonathan Marler <johnnymarler gmail.com> writes:
On Saturday, 3 March 2018 at 00:20:14 UTC, H. S. Teoh wrote:
 On Fri, Mar 02, 2018 at 11:51:08PM +0000, Jonathan Marler via 
 Digitalmars-d wrote:
 [...]
Not true: template counterexample(alias T) {} int x; string s; alias U = counterexample!x; // OK alias V = counterexample!1; // OK alias W = counterexample!"yup"; // OK alias X = counterexample!s; // OK alias Z = counterexample!int; // NG The last one fails because a value is expected, not a type. If you *really* want to accept both values and types, `...` comes to the rescue: template rescue(T...) if (T.length == 1) {} int x; string s; alias U = rescue!x; // OK alias V = rescue!1; // OK alias W = rescue!"yup"; // OK alias X = rescue!s; // OK alias Z = rescue!int; // OK! T
Ah thank you...I guess I didn't realize that literals like 1 and "yup" were considered "symbols" when it comes to alias template parameters.
Mar 02 2018
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/2/18 8:49 PM, Jonathan Marler wrote:
 On Saturday, 3 March 2018 at 00:20:14 UTC, H. S. Teoh wrote:
 On Fri, Mar 02, 2018 at 11:51:08PM +0000, Jonathan Marler via 
 Digitalmars-d wrote:
 [...]
Not true:     template counterexample(alias T) {}     int x;     string s;     alias U = counterexample!x;    // OK     alias V = counterexample!1;    // OK     alias W = counterexample!"yup";    // OK     alias X = counterexample!s;    // OK     alias Z = counterexample!int;    // NG The last one fails because a value is expected, not a type. If you *really* want to accept both values and types, `...` comes to the rescue:     template rescue(T...) if (T.length == 1) {}     int x;     string s;     alias U = rescue!x;    // OK     alias V = rescue!1;    // OK     alias W = rescue!"yup";    // OK     alias X = rescue!s;    // OK     alias Z = rescue!int;    // OK! T
Ah thank you...I guess I didn't realize that literals like 1 and "yup" were considered "symbols" when it comes to alias template parameters.
Well, they aren't. But template alias is a bit of a mess when it comes to the spec. It will accept anything except keywords AFAIK. Would be nice if it just worked like the variadic version. The variadic version is what is usually needed (you see a lot of if(T.length == 1) in std.traits). But, if you wanted to ensure values (which is more akin to your proposal), you can do: template rescue(alias val) if(!is(val)) // not a type -Steve
Mar 05 2018
parent Jonathan Marler <johnnymarler gmail.com> writes:
On Monday, 5 March 2018 at 13:03:50 UTC, Steven Schveighoffer 
wrote:
 On 3/2/18 8:49 PM, Jonathan Marler wrote:
 On Saturday, 3 March 2018 at 00:20:14 UTC, H. S. Teoh wrote:
 On Fri, Mar 02, 2018 at 11:51:08PM +0000, Jonathan Marler via 
 Digitalmars-d wrote:
 [...]
Not true:     template counterexample(alias T) {}     int x;     string s;     alias U = counterexample!x;    // OK     alias V = counterexample!1;    // OK     alias W = counterexample!"yup";    // OK     alias X = counterexample!s;    // OK     alias Z = counterexample!int;    // NG The last one fails because a value is expected, not a type. If you *really* want to accept both values and types, `...` comes to the rescue:     template rescue(T...) if (T.length == 1) {}     int x;     string s;     alias U = rescue!x;    // OK     alias V = rescue!1;    // OK     alias W = rescue!"yup";    // OK     alias X = rescue!s;    // OK     alias Z = rescue!int;    // OK! T
Ah thank you...I guess I didn't realize that literals like 1 and "yup" were considered "symbols" when it comes to alias template parameters.
Well, they aren't. But template alias is a bit of a mess when it comes to the spec. It will accept anything except keywords AFAIK. Would be nice if it just worked like the variadic version. The variadic version is what is usually needed (you see a lot of if(T.length == 1) in std.traits). But, if you wanted to ensure values (which is more akin to your proposal), you can do: template rescue(alias val) if(!is(val)) // not a type -Steve
Thanks for the tip, it looks like the spec does mention "literals" but "alias" parameters are even more versatile than that (https://dlang.org/spec/template.html#TemplateAliasParameter). For example you can pass a function call. I've created an issue to make sure we update the spec to reflect the true capabilities: https://issues.dlang.org/show_bug.cgi?id=18558
Mar 05 2018