Compile time features

qsdf via Digitalmars-d digitalmars-d at puremagic.com
Wed Oct 28 23:02:03 PDT 2015


On Thursday, 29 October 2015 at 02:43:59 UTC, Shammah Chancellor 
wrote:
> Currently D has some very very powerful compile time features, 
> but they can get unwieldily quickly when doing compile time 
> reflection with mildly complicated logic.  It's pretty 
> disappointing.  I'd like to start a discussion around some of 
> the problems I've ran into using these features.  If there 
> aren't bugzilla reports, I can open them but I'm not entirely 
> sure how to file these appropriately.
>
> 1) There seems to be many cases where __traits(allMembers, ...) 
> over a package produces symbol strings which cannot be 
> converted to a symbol using __traits(getMember). Also __traits 
> is not useable in reasonable contexts( alias foo = 
> __traits(..)). E.g.
>
> This will fail due to weird symbols being returned from 
> allMembers.
> ```
> import std.stdio;
>
> enum hack(A...) = A;
>
> int main() {
> 	foreach(member; __traits(allMembers, std.stdio)) {
> 		pragma(msg, member);
> 		alias sym = hack!(__traits(getMember, std.stdio, member))[0];
> 	}
> 	return 0;
> }
> ```
>
> 2) There are oddities around getting the types of functions 
> which are properties:
>
> e.g. (Note the __compiles, and addressing the member):
>
> ```
> //Gets the member type, even for properties.
> private template MemberType(C, string memberName)
> {
>     alias member = TypeTuple!(__traits (getMember, C, 
> memberName))[0];
>
>     static if (__traits (compiles, typeof(&member)))
>     {
>         static if (isSomeFunction!(typeof(&member)))
>         {
>             alias MemberType = typeof(&member);
>         }
>         else
>         {
>             alias MemberType = typeof(member);
>         }
>     } else {
>         alias MemberType = typeof(member);
>     }
> }
> ```
>
> 3) Additionally, any kind of iteration becomes very unwieldy.  
> This kind of code becomes necessary in common cases.  (E.g. 
> pass in a list of packages and reduce to a AliasSeq of type 
> symbols)
>
>
> ```
> import std.stdio : writeln;
> import std.typetuple;
>
> // This won't work:
> /+
> private template stuff(Args...) {
> 	/+ static +/ foreach(Arg; Args) {
> 		...
> 	}
> }
> +/
>
> // Must do this instead:
> private template expand(Args...)
> {
> 	static if (Args.length > 0)
> 	{
> 		static if (Args.length > 1)
> 		{
> 			enum stuff = AliasSeq!(repeat!(Args[0], Args.length), 
> stuff!(Args[1..$]));
> 		}
> 		else static if (Args.length == 1)
> 		{
> 			enum stuff = AliasSeq!(repeat!(Args[0], Args.length));
> 		}
> 	}
> }
>
> private template repeat(alias T, int times) {
> 	static if ( times > 1 ) {
> 		enum repeat = AliasSeq!(T, repeat!(T, times-1));
> 	} else static if (times == 1) {
> 		enum repeat = AliasSeq!(T);
> 	}
> }
>
> enum things = expand!("A","B","C");
>
> void main() {
> 	pragma(msg, things);
> 	writeln("Hello World");
> }
> ```

I agree with you on an aspect: writing code with __traits() often 
leads to a  cascade of "unfriendly", "cryptic", "undigest", 
static if and loops.

However your examples are discutables:

1/ The symbol is not always a type, so to test it there is 
`if(is()){}`:

---
import std.stdio;

enum hack(A...) = A;

int main() {
	foreach(member; __traits(allMembers, std.stdio)) {
		pragma(msg, member);
         static if (is(member))
		    alias sym = hack!(__traits(getMember, std.stdio, 
member))[0];
	}
}
---

2/ with only one way to define the alias it works, whatever is 
the function type (property or not)

---
import std.traits, std.stdio, std.typetuple;

private template MemberType(C, string memberName)
{
     alias member = TypeTuple!(__traits (getMember, C, 
memberName))[0];
     static if (isSomeFunction!(typeof(&member)))
         alias MemberType = typeof(&member);
     else static assert(0, "not handled here !");
}

struct Hop
{
     void foo(uint a){}
     @property uint bar(){return 0;}
     uint baz(){return 0;}
     @property void bla(uint h){}
}

void main()
{
     MemberType!(Hop, "foo").stringof.writeln;
     MemberType!(Hop, "bar").stringof.writeln;
     MemberType!(Hop, "baz").stringof.writeln;
     MemberType!(Hop, "bla").stringof.writeln;
}
---

3/ Your example doesn't compile




More information about the Digitalmars-d mailing list