alias = compile-time variants?

Philippe Sigaud philippe.sigaud at gmail.com
Fri Jul 30 06:16:11 PDT 2010


On Thu, Jul 29, 2010 at 22:40, Jason Spencer <spencer8 at 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d-learn/attachments/20100730/1f9200d1/attachment-0001.html>


More information about the Digitalmars-d-learn mailing list