www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Parameter-less templates?

reply "monarch_dodra" <monarchdodra gmail.com> writes:
D has introduced a pretty cool tool: templates. These are 
basically namespaces that can be instantiated by a type/alias. 
Mixing with them the notion of "eponymous" allows to do some 
seriously cool things with them.

One of the things I find strange though is that they *must* be 
parameterized. This limitation seems entirely artificial to me. 
Why not allow templates without parameters, just the same way 
some functions aren't parameterized. There are useful use-cases 
for this:
* Simple creation of namespaces (as opposed to non-contructible 
struct/classes)
* Allows creating private helpers, without polluting the rest of 
the module (private functions are still callable by other 
functions in the module).

So... yeah, why don't we have this?

--------

Related: I have encountered this problem, and I can't seem to 
work around it; *other* than non-parameterized templates. 
Basically, I have this pred function, we'll call it "foo". This 
pred function can itself be parameterized to take its own 
(optional) pred. This basically allows:
foo(a, b)
or
foo!pred(a, b)

This is "traditionally" solved by doing:
void foo(A, B)(A a, B b);
void foo(alias pred, A, B)(A a, B b);

Here is the kicker though: "foo" is itself a pred. This means 
that I *need* to be able to pass "foo!pred" as a predicate. This 
does not work, as "foo!pred" is nothing: The compiler doesn't 
know what you are talking about, as the parameters A and B are 
missing. This is usually solved by a template:

template foo(alias pred)
{
     void foo(A, B)(A a, B b);
}

This works.... *however* the presence of the "void foo(A, B)(A a, 
B b);" confuses the crap out of the compiler:
foo(a, b); //OK
alias PRED = foo!"hello";
PRED(a, b); //OK

BUT:
foo!"hello"(a, b); //Error:
Error: template hello.foo does not match any function template 
declaration. Candidates are:
hello.foo(R1, R2)(R1 r1, R2 r2)
hello.foo(alias pred)
Error: template hello.foo(R1, R2)(R1 r1, R2 r2) cannot deduce 
template function from argument types !("hello")(int, int)
Error: template instance foo!"hello" errors instantiating template

So... how to make this work? AFAIK, non-parameterized templates 
should solve it. Or is it just a compiler issue?

FYI: This is a problem present in Phobos. You can use:
"equal!equal(RoR1, RoR2)"
To compare two ranges of ranges. equal!equal gets instanciated, 
because the args are present to "finish" the missing R1/R2 args 
after pred.

However, this neat trick stop there:
"equal!(equal!equal)(RoRoR1, RoRoR2)"
This time, this does not work, as the compiler can't resolve the 
predicate.

I'd like to solve this. IMO "equal!equal" is one of the neatest 
"1-word" in D, and I want to make sure it works as one would 
expect it to.

--------

So: Any workaround recommendations? Alternatives? Thoughts on 
parameter-less templates (regardless of my issue)?
Aug 12 2013
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-08-12 21:03, monarch_dodra wrote:
 D has introduced a pretty cool tool: templates. These are basically
 namespaces that can be instantiated by a type/alias. Mixing with them
 the notion of "eponymous" allows to do some seriously cool things with
 them.

 One of the things I find strange though is that they *must* be
 parameterized. This limitation seems entirely artificial to me. Why not
 allow templates without parameters, just the same way some functions
 aren't parameterized. There are useful use-cases for this:
 * Simple creation of namespaces (as opposed to non-contructible
 struct/classes)
 * Allows creating private helpers, without polluting the rest of the
 module (private functions are still callable by other functions in the
 module).

 So... yeah, why don't we have this?

Do you mean like: template Foo () { int a; } Unfortunately this doesn't work: Foo.a = 3; But this does: Foo!().a = 3; -- /Jacob Carlborg
Aug 12 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Monday, 12 August 2013 at 19:58:32 UTC, Jacob Carlborg wrote:
 Do you mean like:

 template Foo ()
 {
     int a;
 }

 Unfortunately this doesn't work:

 Foo.a = 3;

 But this does:

 Foo!().a = 3;

class Foo { static int a; } template Foo() { int a = 0; } void main() { Foo.a = 0; } Wouldn't this be a problem if that syntax was allowed?
Aug 12 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Monday, 12 August 2013 at 19:03:41 UTC, monarch_dodra wrote:
 D has introduced a pretty cool tool: templates. These are 
 basically namespaces that can be instantiated by a type/alias. 
 Mixing with them the notion of "eponymous" allows to do some 
 seriously cool things with them.

 One of the things I find strange though is that they *must* be 
 parameterized.

Yes and no. void foo()() {} is a parameter-less template. As the construct already exists at semantic level, I guess making it available everywhere is the way to go.
Aug 12 2013
prev sibling next sibling parent Kenji Hara <k.hara.pg gmail.com> writes:
--bcaec53f2e310ec28c04e3ce1f66
Content-Type: text/plain; charset=UTF-8

2013/8/13 monarch_dodra <monarchdodra gmail.com>

 Related: I have encountered this problem, and I can't seem to work around
 it; *other* than non-parameterized templates. Basically, I have this pred
 function, we'll call it "foo". This pred function can itself be
 parameterized to take its own (optional) pred. This basically allows:
 foo(a, b)
 or
 foo!pred(a, b)

 This is "traditionally" solved by doing:
 void foo(A, B)(A a, B b);
 void foo(alias pred, A, B)(A a, B b);

 Here is the kicker though: "foo" is itself a pred. This means that I
 *need* to be able to pass "foo!pred" as a predicate. This does not work, as
 "foo!pred" is nothing: The compiler doesn't know what you are talking
 about, as the parameters A and B are missing. This is usually solved by a
 template:

 template foo(alias pred)
 {
     void foo(A, B)(A a, B b);
 }

 This works.... *however* the presence of the "void foo(A, B)(A a, B b);"
 confuses the crap out of the compiler:
 foo(a, b); //OK
 alias PRED = foo!"hello";
 PRED(a, b); //OK

 BUT:
 foo!"hello"(a, b); //Error:
 Error: template hello.foo does not match any function template
 declaration. Candidates are:
 hello.foo(R1, R2)(R1 r1, R2 r2)
 hello.foo(alias pred)
 Error: template hello.foo(R1, R2)(R1 r1, R2 r2) cannot deduce template
 function from argument types !("hello")(int, int)
 Error: template instance foo!"hello" errors instantiating template

 So... how to make this work? AFAIK, non-parameterized templates should
 solve it. Or is it just a compiler issue?

 FYI: This is a problem present in Phobos. You can use:
 "equal!equal(RoR1, RoR2)"
 To compare two ranges of ranges. equal!equal gets instanciated, because
 the args are present to "finish" the missing R1/R2 args after pred.

 However, this neat trick stop there:
 "equal!(equal!equal)(RoRoR1, RoRoR2)"
 This time, this does not work, as the compiler can't resolve the predicate.

 I'd like to solve this. IMO "equal!equal" is one of the neatest "1-word"
 in D, and I want to make sure it works as one would expect it to.

 --------

 So: Any workaround recommendations? Alternatives? Thoughts on
 parameter-less templates (regardless of my issue)?

Maybe: http://d.puremagic.com/issues/show_bug.cgi?id=10811 Kenji Hara --bcaec53f2e310ec28c04e3ce1f66 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">2013/8/13 monarch_dodra <span dir=3D"ltr">&lt;<a href=3D"m= ailto:monarchdodra gmail.com" target=3D"_blank">monarchdodra gmail.com</a>&= gt;</span><br><div class=3D"gmail_extra"><div class=3D"gmail_quote"><blockq= uote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-wi= dth:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-= left:1ex"> Related: I have encountered this problem, and I can&#39;t seem to work arou= nd it; *other* than non-parameterized templates. Basically, I have this pre= d function, we&#39;ll call it &quot;foo&quot;. This pred function can itsel= f be parameterized to take its own (optional) pred. This basically allows:<= br> foo(a, b)<br> or<br> foo!pred(a, b)<br> <br> This is &quot;traditionally&quot; solved by doing:<br> void foo(A, B)(A a, B b);<br> void foo(alias pred, A, B)(A a, B b);<br> <br> Here is the kicker though: &quot;foo&quot; is itself a pred. This means tha= t I *need* to be able to pass &quot;foo!pred&quot; as a predicate. This doe= s not work, as &quot;foo!pred&quot; is nothing: The compiler doesn&#39;t kn= ow what you are talking about, as the parameters A and B are missing. This = is usually solved by a template:<br> <br> template foo(alias pred)<br> {<br> =C2=A0 =C2=A0 void foo(A, B)(A a, B b);<br> }<br> <br> This works.... *however* the presence of the &quot;void foo(A, B)(A a, B b)= ;&quot; confuses the crap out of the compiler:<br> foo(a, b); //OK<br> alias PRED =3D foo!&quot;hello&quot;;<br> PRED(a, b); //OK<br> <br> BUT:<br> foo!&quot;hello&quot;(a, b); //Error:<br> Error: template hello.foo does not match any function template declaration.= Candidates are:<br> hello.foo(R1, R2)(R1 r1, R2 r2)<br> hello.foo(alias pred)<br> Error: template hello.foo(R1, R2)(R1 r1, R2 r2) cannot deduce template func= tion from argument types !(&quot;hello&quot;)(int, int)<br> Error: template instance foo!&quot;hello&quot; errors instantiating templat= e<br> <br> So... how to make this work? AFAIK, non-parameterized templates should solv= e it. Or is it just a compiler issue?<br> <br> FYI: This is a problem present in Phobos. You can use:<br> &quot;equal!equal(RoR1, RoR2)&quot;<br> To compare two ranges of ranges. equal!equal gets instanciated, because the= args are present to &quot;finish&quot; the missing R1/R2 args after pred.<= br> <br> However, this neat trick stop there:<br> &quot;equal!(equal!equal)(RoRoR1, RoRoR2)&quot;<br> This time, this does not work, as the compiler can&#39;t resolve the predic= ate.<br> <br> I&#39;d like to solve this. IMO &quot;equal!equal&quot; is one of the neate= st &quot;1-word&quot; in D, and I want to make sure it works as one would e= xpect it to.<br> <br> --------<br> <br> So: Any workaround recommendations? Alternatives? Thoughts on parameter-les= s templates (regardless of my issue)?<br> </blockquote></div><br></div><div class=3D"gmail_extra">Maybe:=C2=A0<a href= =3D"http://d.puremagic.com/issues/show_bug.cgi?id=3D10811">http://d.puremag= ic.com/issues/show_bug.cgi?id=3D10811</a></div><div class=3D"gmail_extra"><= br></div><div class=3D"gmail_extra"> Kenji Hara</div></div> --bcaec53f2e310ec28c04e3ce1f66--
Aug 12 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Tuesday, 13 August 2013 at 01:08:01 UTC, deadalnix wrote:
 On Monday, 12 August 2013 at 19:03:41 UTC, monarch_dodra wrote:
 D has introduced a pretty cool tool: templates. These are 
 basically namespaces that can be instantiated by a type/alias. 
 Mixing with them the notion of "eponymous" allows to do some 
 seriously cool things with them.

 One of the things I find strange though is that they *must* be 
 parameterized.

Yes and no. void foo()() {} is a parameter-less template. As the construct already exists at semantic level, I guess making it available everywhere is the way to go.

I think strictly speaking, that is a "parameterless parameterized function", as opposed to a "non parameterized function". In regards to template (I mean the actual "template"), I guess I wish we could either: 1. Allow non-parameterized templates (eg template foo {...}) 2. Allow invoking a template without parameters (provided the template has 0 parameters, or default parameters), without doing "!()" But yeah, I think I agree with you, that it should be made available everywhere.
Aug 13 2013
prev sibling next sibling parent "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 13 August 2013 at 09:41:45 UTC, monarch_dodra wrote:
 I think strictly speaking, that is a "parameterless 
 parameterized function", as opposed to a "non parameterized 
 function".

No, this is simply syntax sugar on top of eponymous template declaration.
 In regards to template (I mean the actual "template"), I guess 
 I wish we could either:
 1. Allow non-parameterized templates (eg template foo {...})
 2. Allow invoking a template without parameters (provided the 
 template has 0 parameters, or default parameters), without 
 doing "!()"

Amen !
Aug 13 2013
prev sibling parent "Tommi" <tommitissari hotmail.com> writes:
On Tuesday, 13 August 2013 at 09:41:45 UTC, monarch_dodra wrote:
 In regards to template (I mean the actual "template"), I guess 
 I wish we could either:
 1. Allow non-parameterized templates (eg template foo {...})
 2. Allow invoking a template without parameters (provided the 
 template has 0 parameters, or default parameters), without 
 doing "!()"

I think your proposal no. 1 is good, but there's a problem with your proposal no. 2. This is current D code: template get(int n = 1) { static if (n == 1) { alias get = one; } else static if (n == 0) { enum get = 0; } } template one(int n) { enum one = 1; } template wrap(alias a) { enum wrap = a!0; } void main() { static assert(wrap!get == 0); static assert(wrap!(get!()) == 1); } So, if we go with your proposal no. 2 (allow invoking a template without a parameter list), then the meaning of 'get' in: wrap!get ...becomes ambiguous. We could be either passing an alias to 'get', or an alias to a parameterless instantiation of template 'get', i.e. get!().
Aug 14 2013