www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - alias = compile-time variants?

reply Jason Spencer <spencer8 sbcglobal.net> writes:
In writing templates that make heavy use of alias parameters, does
anyone else feel uneasy about whether the caller will pass a type, a
value, or a schmoo?  I'm having a hard time getting my head around
how wide-open aliases are and trying to resist the urge to put in
thousands of static asserts to check what should be invariants on
the kind of thing that can be passed in that position.  This all
feels very strange when I typically look for templates to provide
that nice, static, compile-time safety that keeps me from having to
check everything that gets passed.  Any words of wisdom on adjusting
to this feature?

Thanx,
Jason
Jul 29 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Jason Spencer:
 In writing templates that make heavy use of alias parameters, does
 anyone else feel uneasy about whether the caller will pass a type, a
 value, or a schmoo?

Normally D is a mostly statically typed language (objects have a dynamic type), but sometimes template juggling is purely dynamically typed. See also: http://d.puremagic.com/issues/show_bug.cgi?id=3881 Being able to avoid the 'alias' and pass structs, templates and arrays (curiously char/wchar/dchar arrays are allowed, but not other types of arrays) to templates can be positive to avoid some troubles caused by alias template arguments. Bye, bearophile
Jul 29 2010
prev sibling next sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
--0016e6d58a039d35e2048c9aa7e2
Content-Type: text/plain; charset=ISO-8859-1

On Thu, Jul 29, 2010 at 22:40, Jason Spencer <spencer8 sbcglobal.net> wrote:

 In writing templates that make heavy use of alias parameters, does
 anyone else feel uneasy about whether the caller will pass a type, a
 value, or a schmoo?

I thought they could only be symbols. That is, an alias is a 'link', a sort of pointer to a symbol: a template name, a module name, a function name, etc. It does not seem to accept types: template TestAlias(alias a) { enum string TestAlias = __traits(identifier, a); } void main() { T foo(T)(T t) { return t;} writeln(TestAlias!foo); // works writeln(TestAlias!int); // do not compile } Though '3' is accepted by alias... Hmm.
 I'm having a hard time getting my head around
 how wide-open aliases are and trying to resist the urge to put in
 thousands of static asserts to check what should be invariants on
 the kind of thing that can be passed in that position.  This all
 feels very strange when I typically look for templates to provide
 that nice, static, compile-time safety that keeps me from having to
 check everything that gets passed.  Any words of wisdom on adjusting
 to this feature?

Wisdom, I don't know, as I still feel like I'm exploring things. But template constraints are there to limit what you can instantiate. The C++ syntax is still there (T : U, etc), but it's quite limited and not so easy to parse, compared to D template constraints. Feel free to ignore what follows if that's well-treaded ground to you. Say I have a template that takes an alias, fun, and a type, T. fun is supposed to be a function, but in fact why limit it to that? What I need is for foo to be callable with a T. So let's test for that: auto doSomething(alias fun, T)(T t) if (is(typeof( fun(T.init) ))) { // now that I'm here, I can freely use fun as a callable on any T auto result = fun(t); // ... } So, T is a type. T.init is a value of type T, the default value for any T. .init is a easy way to generate a value from a type. Any type in D has a .init field (not typetuples, though). Note that 't' is not really accessible inside the constraint template, because t will have a runtime value, whereas here we are at compile-time. I think t can be used, but is still T.init at this stage. I call fun with T.init. If that compiles, then the resulting expression has a type: I use typeof() to get it, and then the is() expression to get a bool telling me if that's a valid type. If foo(T.init) doesn't compile, for whatever reason (fun as no opCall defined, or foo is callable, but not with a T...) then foo(T.init) has no type, so is(typeof( ... )) returns false and the template constraint forbids the template to be instantiated. inside doSomething(), I can freely use fun as something callable with one T. Note that my constraint is not complete: I did not test for fun(T.init) to return a value: it could be a void function(T) and the assignement would fail. I could also test for that, I guess. Philippe --0016e6d58a039d35e2048c9aa7e2 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <br><br><div class=3D"gmail_quote">On Thu, Jul 29, 2010 at 22:40, Jason Spe= ncer <span dir=3D"ltr">&lt;<a href=3D"mailto:spencer8 sbcglobal.net">spence= r8 sbcglobal.net</a>&gt;</span> wrote:<br><blockquote class=3D"gmail_quote"= style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"> In writing templates that make heavy use of alias parameters, does<br> anyone else feel uneasy about whether the caller will pass a type, a<br> value, or a schmoo? =A0</blockquote><div><br></div><div>I thought they coul= d only be symbols. That is, an alias is a &#39;link&#39;, a sort of pointer= to a symbol: a template name, a module name, a function name, etc.</div> <div>It does not seem to accept types:</div><div><br></div><div><div>templa= te TestAlias(alias a)</div><div>{</div><div>=A0=A0 =A0enum string TestAlias= =3D __traits(identifier, a);</div><div>}</div><div><br></div><div>void mai= n()</div> <div>{</div><div>=A0=A0 =A0T foo(T)(T t) { return t;}</div><div>=A0=A0 =A0w= riteln(TestAlias!foo); // works</div><div>=A0=A0 =A0writeln(TestAlias!int);= // do not compile</div><div>}</div></div><div><br></div><div>Though &#39;3= &#39; is accepted by alias... Hmm.</div> <div><br></div><div>=A0</div><blockquote class=3D"gmail_quote" style=3D"mar= gin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">I&#39;m having= a hard time getting my head around<br> how wide-open aliases are and trying to resist the urge to put in<br> thousands of static asserts to check what should be invariants on<br> the kind of thing that can be passed in that position. =A0This all<br> feels very strange when I typically look for templates to provide<br> that nice, static, compile-time safety that keeps me from having to<br> check everything that gets passed. =A0Any words of wisdom on adjusting<br> to this feature?</blockquote><div><br></div><div>Wisdom, I don&#39;t know, = as I still feel like I&#39;m exploring things. But template=A0constraints a= re there to limit what you can instantiate. The C++ syntax is still there (= T : U, etc), but it&#39;s quite limited and not so easy to parse, compared = to D template constraints.</div> <div><br></div><div>Feel free to ignore what follows if that&#39;s well-tre= aded ground to you.</div><div><br></div><div>Say I have a template that tak= es an alias, fun, and a type, T.=A0</div><div>fun is supposed to be a funct= ion, but in fact why limit it to that? What I need is for foo to be callabl= e with a T. So let&#39;s test for that:</div> <div><br></div><div>auto doSomething(alias fun, T)(T t)</div><div>if (is(ty= peof( fun(T.init) )))</div><div>{=A0</div><div>// now that I&#39;m here, I = can freely use fun as a callable on any T</div><div>=A0auto result =3D fun(= t);</div> <div>// ...</div><div>}</div><div><br></div><div>So, T is a type. T.init is= a value of type T, the default value for any T. .init is a easy way to gen= erate a value from a type. Any type in D has a .init field (not typetuples,= though). Note that &#39;t&#39; is not really accessible inside the constra= int template, because t will have a runtime value, whereas here we are at c= ompile-time. I think t can be used, but is still T.init at this stage.</div=

lting expression has a type: I use typeof() to get it, and then the is() ex= pression to get a bool telling me if that&#39;s a valid type. If foo(T.init= ) doesn&#39;t compile, for whatever reason (fun as no opCall defined, or fo= o is callable, but not with a T...) then foo(T.init) has no type, so is(typ= eof( ... )) returns false and the template constraint forbids the template = to be instantiated.</div> <div><br></div><div>inside doSomething(), I can freely use fun as something= callable with one T.</div><div>Note that my constraint is not complete: I = did not test for fun(T.init) to return a value: it could be a void function= (T) and the assignement would fail. I could also test for that, I guess.</d= iv> <div><br></div><div>Philippe</div><div><br></div></div> --0016e6d58a039d35e2048c9aa7e2--
Jul 30 2010
parent reply Jason Spencer <spencer8 sbcglobal.net> writes:
== Quote from Philippe Sigaud (philippe.sigaud gmail.com)'s article
 --0016e6d58a039d35e2048c9aa7e2

 I thought they could only be symbols. That is, an alias is a 'link',

 of pointer to a symbol: a template name, a module name, a function
 name, etc.

Whatever confidence you inspired by removing type from the list is quickly lost and more when you add module name--I hadn't thought of that! :)
 Wisdom, I don't know, as I still feel like I'm exploring things. But
 template constraints are there to limit what you can instantiate.
 ...
 Say I have a template that takes an alias, fun, and a type, T.
 fun is supposed to be a function, but in fact why limit it to that?
 What I need is for foo to be callable with a T. So let's test for
 that:
 auto doSomething(alias fun, T)(T t)
 if (is(typeof( fun(T.init) )))
 {
 // now that I'm here, I can freely use fun as a callable on any T
  auto result = fun(t);
 // ...
 }

I understand this example, and (most of) the mechanics of constraints. What I'm not so sure about is the recommended practice around their use. I see lot's of code that doesn't check those things. Suppose you left off the constraint and did: class Foo(U){} doSomething!(Foo, int)(3) it seems like there's a good chance you could get: auto result = Foo!(int); // type inferred from 3 (since this doesn't actually work like I'm saying, please conveniently imagine a similar case that does. :) Even with your constraint, I'm not sure I feel any more comfortable. If it compiles in the body of doSomething, it will compile in the constraint--not sure I've added any value. So how do you sleep at night not knowing if there's some funky syntax on somebody's template-that-takes-a-template which, when combined with some inference, might look like your function call on a value param? My initial reaction is to specify the hell out of the constraints, but I couldn't beat the feeling I was going overboard. I suspect that most people rely on the fact that most improper calls won't compile. Maybe I'm still too new to the syntax to have a good feel for what will get caught, and what could interpreted by the compiler in multiple ways depending on the actual arguments. So, do folks write constraints to ensure that modules don't get passed to their templates? :) Jason
Jul 31 2010
parent Lutger <lutger.blijdestijn gmail.com> writes:
Jason Spencer wrote:

 == Quote from Philippe Sigaud (philippe.sigaud gmail.com)'s article
 --0016e6d58a039d35e2048c9aa7e2

 I thought they could only be symbols. That is, an alias is a 'link',

 of pointer to a symbol: a template name, a module name, a function
 name, etc.

Whatever confidence you inspired by removing type from the list is quickly lost and more when you add module name--I hadn't thought of that! :)
 Wisdom, I don't know, as I still feel like I'm exploring things. But
 template constraints are there to limit what you can instantiate.
 ...
 Say I have a template that takes an alias, fun, and a type, T.
 fun is supposed to be a function, but in fact why limit it to that?
 What I need is for foo to be callable with a T. So let's test for
 that:
 auto doSomething(alias fun, T)(T t)
 if (is(typeof( fun(T.init) )))
 {
 // now that I'm here, I can freely use fun as a callable on any T
  auto result = fun(t);
 // ...
 }

I understand this example, and (most of) the mechanics of constraints. What I'm not so sure about is the recommended practice around their use. I see lot's of code that doesn't check those things. Suppose you left off the constraint and did: class Foo(U){} doSomething!(Foo, int)(3) it seems like there's a good chance you could get: auto result = Foo!(int); // type inferred from 3 (since this doesn't actually work like I'm saying, please conveniently imagine a similar case that does. :)

Sure, but that would be quite a gotcha since you went from calling something to merely instantiating a template. Perhaps there are such gotcha's, I am not aware of them.
 Even with your constraint, I'm not sure I feel any more comfortable.
 If it compiles in the body of doSomething, it will compile in the
 constraint--not sure I've added any value.

Perhaps not in this case, but: - constraints add documentation, such as isInputRange!T or IsCallable!fun - you can add a constraint that may not be statically checked inside the body of the template. This way you can still reject template parameters considered to be invalid even if the template body *could* be instantiated with them. - a constraint is a nice place to add better compiler error messages
 So how do you sleep at night not knowing if there's some funky syntax
 on somebody's template-that-takes-a-template which, when combined with
 some inference, might look like your function call on a value param?
 My initial reaction is to specify the hell out of the constraints, but
 I couldn't beat the feeling I was going overboard.  I suspect that
 most people rely on the fact that most improper calls won't compile.
 Maybe I'm still too new to the syntax to have a good feel for what
 will get caught, and what could interpreted by the compiler in
 multiple ways depending on the actual arguments.
 
 So, do folks write constraints to ensure that modules don't get passed
 to their templates?  :)
 
 Jason

Why not? As long as your module does the right thing, it may be used to instantiate my template :)
Jul 31 2010
prev sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
--00151747c0705ef300048cc9244c
Content-Type: text/plain; charset=ISO-8859-1

On Sat, Jul 31, 2010 at 21:17, Lutger <lutger.blijdestijn gmail.com> wrote:

 Jason Spencer wrote:

 == Quote from Philippe Sigaud (philippe.sigaud gmail.com)'s article
 --0016e6d58a039d35e2048c9aa7e2

 I thought they could only be symbols. That is, an alias is a 'link',

 of pointer to a symbol: a template name, a module name, a function
 name, etc.

Whatever confidence you inspired by removing type from the list is quickly lost and more when you add module name--I hadn't thought of that! :)


I discovered it by error, IIRC. That and the fact that template-like statements like auto members = __traits(allMembers, std.stdio); work. Try it, print the result. Though I do not know what to do with it :)
 Wisdom, I don't know, as I still feel like I'm exploring things. But
 template constraints are there to limit what you can instantiate.
 ...
 Say I have a template that takes an alias, fun, and a type, T.
 fun is supposed to be a function, but in fact why limit it to that?
 What I need is for foo to be callable with a T. So let's test for
 that:
 auto doSomething(alias fun, T)(T t)
 if (is(typeof( fun(T.init) )))
 {
 // now that I'm here, I can freely use fun as a callable on any T
  auto result = fun(t);
 // ...
 }

I understand this example, and (most of) the mechanics of constraints. What I'm not so sure about is the recommended practice around their use. I see lot's of code that doesn't check those things. Suppose you left off the constraint and did: class Foo(U){} doSomething!(Foo, int)(3) it seems like there's a good chance you could get: auto result = Foo!(int); // type inferred from 3 (since this doesn't actually work like I'm saying, please conveniently imagine a similar case that does. :)

Sure, but that would be quite a gotcha since you went from calling something to merely instantiating a template. Perhaps there are such gotcha's, I am not aware of them.

You can test for the alias to be a function (is(typeof(a) == function)), a delegate, or you can test for the presence of an opCall operator (the '()' operator), with __traits(hasMember, alias, "opCall") I think there should be a isCallable trait in Phobos... But in the opCall case, the gotcha is the class templates are not classes. Only instantiated classes are really classes. That is, given class C(T) { T t; T opCall(T u) { return t;} } __traits(hasMember, C, "opCall") will answer 'false'. That's normal, since C is not a class, but a template, of type void. __traits(hasMember, C!int, "opCall") will answer 'true'.
 Even with your constraint, I'm not sure I feel any more comfortable.
 If it compiles in the body of doSomething, it will compile in the
 constraint--not sure I've added any value.

Perhaps not in this case, but: - constraints add documentation, such as isInputRange!T or IsCallable!fun - you can add a constraint that may not be statically checked inside the body of the template. This way you can still reject template parameters considered to be invalid even if the template body *could* be instantiated with them.

I never thought of that.
 - a constraint is a nice place to add better compiler error messages

Except the compiler just say it cannot instantiate the template NameWithConstraints.
 So how do you sleep at night not knowing if there's some funky syntax
 on somebody's template-that-takes-a-template which, when combined with
 some inference, might look like your function call on a value param?
 My initial reaction is to specify the hell out of the constraints, but
 I couldn't beat the feeling I was going overboard.  I suspect that
 most people rely on the fact that most improper calls won't compile.


Yes.
 Maybe I'm still too new to the syntax to have a good feel for what
 will get caught, and what could interpreted by the compiler in
 multiple ways depending on the actual arguments.


I have nothing against long and well-documented constraints. I feel we are not using them as much as we could. With things like staticMap and such, you can do a lot!
 So, do folks write constraints to ensure that modules don't get passed
 to their templates?  :)

 Jason

Why not? As long as your module does the right thing, it may be used to instantiate my template :)

You can try to define an isTemplate template, and a isModule template :-) Look at this: T foo(T)(T t) { return t;} class C(T) { T t; T opCall(T u) { return t;} } template Describe(alias a) { enum string Name = a.stringof; enum string Ident = __traits(identifier, a); } void main() { writeln(Describe!(foo).Name); // foo(T) writeln(Describe!(foo).Ident); // foo writeln(Describe!(C).Name); // C(T) writeln(Describe!(C).Ident); // C writeln(Describe!(C!int).Name); // C (really, I thought that would be C!(int). I remember devising a way to extract the types from a template writeln(Describe!(C!int).Ident); // C writeln(Describe!(Describe).Name); // Calling it on itself! Describe(alias a) writeln(Describe!(Describe).Ident); // Describe writeln(Describe!(std.stdio).Name); // module stdio Strange, no std. in sight. writeln(Describe!(std.stdio).Ident); // stdio } So, inside a template a.stringof gives "module a" if a is a module, except it seems to cut anything before a dot. I do not like relying on .stringof, because it's undocumented and not always perfectly coherent. But a pragmatic implementation of isModule could be: template isModule(alias symbol) { enum bool isModule = (symbol.stringof[0..7] == "module "); } :-) Philippe --00151747c0705ef300048cc9244c Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <div class=3D"gmail_quote">On Sat, Jul 31, 2010 at 21:17, Lutger <span dir= =3D"ltr">&lt;<a href=3D"mailto:lutger.blijdestijn gmail.com">lutger.blijdes= tijn gmail.com</a>&gt;</span> wrote:<br><blockquote class=3D"gmail_quote" s= tyle=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"> <div><div></div><div class=3D"h5">Jason Spencer wrote:<br> <br> &gt; =3D=3D Quote from Philippe Sigaud (<a href=3D"mailto:philippe.sigaud g= mail.com">philippe.sigaud gmail.com</a>)&#39;s article<br> &gt;&gt; --0016e6d58a039d35e2048c9aa7e2<br> &gt;&gt;<br> &gt;&gt; I thought they could only be symbols. That is, an alias is a &#39;= link&#39;,<br> &gt; a sort<br> &gt;&gt; of pointer to a symbol: a template name, a module name, a function= <br> &gt;&gt; name, etc.<br> &gt;<br> &gt; Whatever confidence you inspired by removing type from the list is<br> &gt; quickly lost and more when you add module name--I hadn&#39;t thought o= f<br> &gt; that! :)<br></div></div></blockquote><div><br></div><div>I discovered = it by error, IIRC. That and the fact that template-like statements like</di= v><div><br></div><div>auto members =3D __traits(allMembers, std.stdio);</di= v> <div><br></div><div>work. =A0Try it, print the result. Though I do not know= what to do with it :)</div><div>=A0</div><blockquote class=3D"gmail_quote"= style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><= div> <div class=3D"h5"> &gt;<br> &gt;<br> &gt;&gt; Wisdom, I don&#39;t know, as I still feel like I&#39;m exploring t= hings. But<br> &gt;&gt; template constraints are there to limit what you can instantiate.<= br> &gt;&gt; ...<br> &gt;&gt; Say I have a template that takes an alias, fun, and a type, T.<br> &gt;&gt; fun is supposed to be a function, but in fact why limit it to that= ?<br> &gt;&gt; What I need is for foo to be callable with a T. So let&#39;s test = for<br> &gt;&gt; that:<br> &gt;&gt; auto doSomething(alias fun, T)(T t)<br> &gt;&gt; if (is(typeof( fun(T.init) )))<br> &gt;&gt; {<br> &gt;&gt; // now that I&#39;m here, I can freely use fun as a callable on an= y T<br> &gt;&gt; =A0auto result =3D fun(t);<br> &gt;&gt; // ...<br> &gt;&gt; }<br> &gt;<br> &gt; I understand this example, and (most of) the mechanics of constraints.= <br> &gt; What I&#39;m not so sure about is the recommended practice around thei= r<br> &gt; use. =A0I see lot&#39;s of code that doesn&#39;t check those things. = =A0Suppose<br> &gt; you left off the constraint and did:<br> &gt;<br> &gt; class Foo(U){}<br> &gt; doSomething!(Foo, int)(3)<br> &gt;<br> &gt; it seems like there&#39;s a good chance you could get:<br> &gt;<br> &gt; auto result =3D Foo!(int); =A0// type inferred from 3<br> &gt;<br> &gt; (since this doesn&#39;t actually work like I&#39;m saying, please conv= eniently<br> &gt; imagine a similar case that does. :)<br> <br> </div></div>Sure, but that would be quite a gotcha since you went from call= ing something to<br> merely instantiating a template. Perhaps there are such gotcha&#39;s, I am = not aware<br> of them.<br></blockquote><div><br></div><div>You can test for the alias to = be a function (is(typeof(a) =3D=3D function)), a delegate, or you can test = for the presence of an opCall operator (the &#39;()&#39; operator), with __= traits(hasMember, alias, &quot;opCall&quot;)</div> <div>I think there should be a isCallable trait in Phobos...</div><div>But = in the opCall case, the gotcha is the class templates are not classes. Only= instantiated classes are really classes.</div><div>That is, given</div> <div><br></div><div>class C(T)</div><div>{</div><div>=A0T t;</div><div>=A0T= opCall(T u) { return t;}</div><div>}</div><div><br></div><div>__traits(has= Member, C, &quot;opCall&quot;) will answer &#39;false&#39;. That&#39;s norm= al, since C is not a class, but a template, of type void.</div> <div>__traits(hasMember, C!int, &quot;opCall&quot;) will answer &#39;true&#= 39;.</div><div><br></div><div><br></div><div><br></div><div>=A0</div><block= quote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc= solid;padding-left:1ex;"> <div class=3D"im"><br> &gt; Even with your constraint, I&#39;m not sure I feel any more comfortabl= e.<br> &gt; If it compiles in the body of doSomething, it will compile in the<br> &gt; constraint--not sure I&#39;ve added any value.<br> <br> </div>Perhaps not in this case, but:<br> - constraints add documentation, such as isInputRange!T or IsCallable!fun<b= r> - you can add a constraint that may not be statically checked inside the bo= dy of<br> the template. This way you can still reject template parameters considered = to be<br> invalid even if the template body *could* be instantiated with them.<br></b= lockquote><div><br></div><div>I never thought of that.</div><div>=A0</div><= blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px= #ccc solid;padding-left:1ex;"> - a constraint is a nice place to add better compiler error messages<br></b= lockquote><div><br></div><div>Except the compiler just say it cannot instan= tiate the template NameWithConstraints.=A0</div><div><br></div><div>=A0</di= v> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex;"><div class=3D"im"> &gt; So how do you sleep at night not knowing if there&#39;s some funky syn= tax<br> &gt; on somebody&#39;s template-that-takes-a-template which, when combined = with<br> &gt; some inference, might look like your function call on a value param?<b= r> &gt; My initial reaction is to specify the hell out of the constraints, but= <br> &gt; I couldn&#39;t beat the feeling I was going overboard. =A0I suspect th= at<br> &gt; most people rely on the fact that most improper calls won&#39;t compil= e.<br></div></blockquote><div><br></div><div>Yes.=A0</div><div>=A0</div><bl= ockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #= ccc solid;padding-left:1ex;"> <div class=3D"im"> &gt; Maybe I&#39;m still too new to the syntax to have a good feel for what= <br> &gt; will get caught, and what could interpreted by the compiler in<br> &gt; multiple ways depending on the actual arguments.<br></div></blockquote=
<div><br></div><div>I have nothing against long and well-documented constr=

taticMap and such, you can do a lot!</div> <div><br></div><div>=A0</div><blockquote class=3D"gmail_quote" style=3D"mar= gin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><div class=3D"= im"> &gt;<br> &gt; So, do folks write constraints to ensure that modules don&#39;t get pa= ssed<br> &gt; to their templates? =A0:)<br> &gt;<br> &gt; Jason<br> <br> </div>Why not? As long as your module does the right thing, it may be used = to<br> instantiate my template :)<br> </blockquote></div><br><div>You can try to define an isTemplate template, a= nd a isModule template :-)</div><div><br></div><div>Look at this:</div><div=
<br></div><div><div>T foo(T)(T t) { return t;}</div><div><br></div><div>

l(T u) { return t;}</div><div>}</div><div><br></div><div>template Describe(= alias a)</div><div>{</div><div>=A0=A0 =A0enum string Name =3D a.stringof;</= div><div>=A0=A0 =A0enum string Ident =3D __traits(identifier, a);</div> <div>}</div><div><br></div><div>void main()</div><div>{</div><div>=A0=A0 = =A0writeln(Describe!(foo).Name); // foo(T)</div><div>=A0=A0 =A0writeln(Desc= ribe!(foo).Ident); // foo</div><div>=A0=A0 =A0writeln(Describe!(C).Name); /= / C(T)</div><div> =A0=A0 =A0writeln(Describe!(C).Ident); // C</div><div>=A0=A0 =A0writeln(Des= cribe!(C!int).Name); // C (really, I thought that would be C!(int). I remem= ber devising a way to extract the types from a template</div><div>=A0=A0 = =A0writeln(Describe!(C!int).Ident); // C</div> <div><br></div><div>=A0=A0 =A0writeln(Describe!(Describe).Name); // Calling= it on itself! =A0Describe(alias a)</div><div>=A0=A0 =A0writeln(Describe!(D= escribe).Ident); // Describe</div><div><br></div><div>=A0=A0 =A0writeln(Des= cribe!(std.stdio).Name); // module stdio =A0 Strange, no std. in sight.</di= v> <div>=A0=A0 =A0writeln(Describe!(std.stdio).Ident); // stdio</div></div><di= v>}</div><div><br></div><div>So, inside a template a.stringof gives &quot;m= odule a&quot; if a is a module, except it seems to cut anything before a do= t. I do not like relying on .stringof, because it&#39;s undocumented and no= t always perfectly coherent. But a pragmatic implementation of isModule cou= ld be:</div> <div><br></div><div>template isModule(alias symbol)</div><div>{</div><div>= =A0=A0enum bool isModule =3D (symbol.stringof[0..7] =3D=3D &quot;module &qu= ot;);</div><div>}</div><div><br></div><div><br></div><div>:-)</div><div><br=
</div>

--00151747c0705ef300048cc9244c--
Aug 01 2010