<div class="gmail_quote">On Sat, Jul 31, 2010 at 21:17, Lutger <span dir="ltr"><<a href="mailto:lutger.blijdestijn@gmail.com">lutger.blijdestijn@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div><div></div><div class="h5">Jason Spencer wrote:<br>
<br>
> == Quote from Philippe Sigaud (<a href="mailto:philippe.sigaud@gmail.com">philippe.sigaud@gmail.com</a>)'s article<br>
>> --0016e6d58a039d35e2048c9aa7e2<br>
>><br>
>> I thought they could only be symbols. That is, an alias is a 'link',<br>
> a sort<br>
>> of pointer to a symbol: a template name, a module name, a function<br>
>> name, etc.<br>
><br>
> Whatever confidence you inspired by removing type from the list is<br>
> quickly lost and more when you add module name--I hadn't thought of<br>
> that! :)<br></div></div></blockquote><div><br></div><div>I discovered it by error, IIRC. That and the fact that template-like statements like</div><div><br></div><div>auto members = __traits(allMembers, std.stdio);</div>
<div><br></div><div>work. Try it, print the result. Though I do not know what to do with it :)</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><div>
<div class="h5">
><br>
><br>
>> Wisdom, I don't know, as I still feel like I'm exploring things. But<br>
>> template constraints are there to limit what you can instantiate.<br>
>> ...<br>
>> Say I have a template that takes an alias, fun, and a type, T.<br>
>> fun is supposed to be a function, but in fact why limit it to that?<br>
>> What I need is for foo to be callable with a T. So let's test for<br>
>> that:<br>
>> auto doSomething(alias fun, T)(T t)<br>
>> if (is(typeof( fun(T.init) )))<br>
>> {<br>
>> // now that I'm here, I can freely use fun as a callable on any T<br>
>> auto result = fun(t);<br>
>> // ...<br>
>> }<br>
><br>
> I understand this example, and (most of) the mechanics of constraints.<br>
> What I'm not so sure about is the recommended practice around their<br>
> use. I see lot's of code that doesn't check those things. Suppose<br>
> you left off the constraint and did:<br>
><br>
> class Foo(U){}<br>
> doSomething!(Foo, int)(3)<br>
><br>
> it seems like there's a good chance you could get:<br>
><br>
> auto result = Foo!(int); // type inferred from 3<br>
><br>
> (since this doesn't actually work like I'm saying, please conveniently<br>
> imagine a similar case that does. :)<br>
<br>
</div></div>Sure, but that would be quite a gotcha since you went from calling something to<br>
merely instantiating a template. Perhaps there are such gotcha'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) == function)), a delegate, or you can test for the presence of an opCall operator (the '()' operator), with __traits(hasMember, alias, "opCall")</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> T t;</div><div> T opCall(T u) { return t;}</div><div>}</div><div><br></div><div>__traits(hasMember, C, "opCall") will answer 'false'. That's normal, since C is not a class, but a template, of type void.</div>
<div>__traits(hasMember, C!int, "opCall") will answer 'true'.</div><div><br></div><div><br></div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="im"><br>
> Even with your constraint, I'm not sure I feel any more comfortable.<br>
> If it compiles in the body of doSomething, it will compile in the<br>
> constraint--not sure I've added any value.<br>
<br>
</div>Perhaps not in this case, but:<br>
- constraints add documentation, such as isInputRange!T or IsCallable!fun<br>
- you can add a constraint that may not be statically checked inside the body 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></blockquote><div><br></div><div>I never thought of that.</div><div> </div><blockquote class="gmail_quote" style="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></blockquote><div><br></div><div>Except the compiler just say it cannot instantiate the template NameWithConstraints. </div><div><br></div><div> </div>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><div class="im">
> So how do you sleep at night not knowing if there's some funky syntax<br>
> on somebody's template-that-takes-a-template which, when combined with<br>
> some inference, might look like your function call on a value param?<br>
> My initial reaction is to specify the hell out of the constraints, but<br>
> I couldn't beat the feeling I was going overboard. I suspect that<br>
> most people rely on the fact that most improper calls won't compile.<br></div></blockquote><div><br></div><div>Yes. </div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="im">
> Maybe I'm still too new to the syntax to have a good feel for what<br>
> will get caught, and what could interpreted by the compiler in<br>
> multiple ways depending on the actual arguments.<br></div></blockquote><div><br></div><div>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!</div>
<div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><div class="im">
><br>
> So, do folks write constraints to ensure that modules don't get passed<br>
> to their templates? :)<br>
><br>
> 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, and 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>
class C(T)</div><div>{</div><div> T t;</div><div> T opCall(T u) { return t;}</div><div>}</div><div><br></div><div>template Describe(alias a)</div><div>{</div><div> enum string Name = a.stringof;</div><div> enum string Ident = __traits(identifier, a);</div>
<div>}</div><div><br></div><div>void main()</div><div>{</div><div> writeln(Describe!(foo).Name); // foo(T)</div><div> writeln(Describe!(foo).Ident); // foo</div><div> writeln(Describe!(C).Name); // C(T)</div><div>
writeln(Describe!(C).Ident); // C</div><div> 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</div><div> writeln(Describe!(C!int).Ident); // C</div>
<div><br></div><div> writeln(Describe!(Describe).Name); // Calling it on itself! Describe(alias a)</div><div> writeln(Describe!(Describe).Ident); // Describe</div><div><br></div><div> writeln(Describe!(std.stdio).Name); // module stdio Strange, no std. in sight.</div>
<div> writeln(Describe!(std.stdio).Ident); // stdio</div></div><div>}</div><div><br></div><div>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:</div>
<div><br></div><div>template isModule(alias symbol)</div><div>{</div><div> enum bool isModule = (symbol.stringof[0..7] == "module ");</div><div>}</div><div><br></div><div><br></div><div>:-)</div><div><br></div>
<div>Philippe</div><div><br></div>