Re: Introduction to traits (and __traits)
Am 30.08.2013 21:36, schrieb Joseph Rushton Wakeling: Hello all, I find myself wanting to write for the first time one of these isSomething(T) or hasSomething(T) templates that perform compile-time checks, so I was hoping people could give me some good general advice on traits. The goal here is to be able to confirm (i) type T has certain members and (ii) they have certain properties. (This is for my graph library, Dgraph.) So, to start off with, I thought I'd try starting with, template isGraph(G) { isGraph = __traits(hasMember, G, directed) isBoolean!(typeof(G.directed)); } ... which I'd assumed would cover the case where G does not have a member directed. But in fact if I pass it a struct that does not have the entity .directed defined therein, it will return an error: no property 'directed' for type ... So, can someone give me a good idea of how to go about writing such a compile-time template that checks (i) for the existence of certain methods/functions/members and (ii) confirms their characteristics, such as their return values or arguments? Thanks best wishes, -- Joe You need to put it into a static if, otherwise the compiler will continue semantic checks on the second part of the expression. E.g. template isGraph(G) { static if(__traits(hasMember, G, directed)) enum bool isGraph = isBoolean!(typeof(G.directed)); else enum bool isGraph = false; }
Introduction to traits (and __traits)
Hello all, I find myself wanting to write for the first time one of these isSomething(T) or hasSomething(T) templates that perform compile-time checks, so I was hoping people could give me some good general advice on traits. The goal here is to be able to confirm (i) type T has certain members and (ii) they have certain properties. (This is for my graph library, Dgraph.) So, to start off with, I thought I'd try starting with, template isGraph(G) { isGraph = __traits(hasMember, G, directed) isBoolean!(typeof(G.directed)); } ... which I'd assumed would cover the case where G does not have a member directed. But in fact if I pass it a struct that does not have the entity .directed defined therein, it will return an error: no property 'directed' for type ... So, can someone give me a good idea of how to go about writing such a compile-time template that checks (i) for the existence of certain methods/functions/members and (ii) confirms their characteristics, such as their return values or arguments? Thanks best wishes, -- Joe
Re: Introduction to traits (and __traits)
On 30/08/13 21:40, Benjamin Thaut wrote: You need to put it into a static if, otherwise the compiler will continue semantic checks on the second part of the expression. E.g. template isGraph(G) { static if(__traits(hasMember, G, directed)) enum bool isGraph = isBoolean!(typeof(G.directed)); else enum bool isGraph = false; } Ahh, right, thanks. :-) Is there a recommended way for handling the case where there are many such members -- say about 10 or more? The static if's could become very highly nested with this approach. I suppose I could go through like this: static if(!__traits(hasMember, G, one)) enum bool isGraph = false; else static if(!__traits(hasMember, G, two)) enum bool isGraph = false; else static if ... ... else { // Now I know all the members exist and I can // start checking out their properties ... }
Re: Introduction to traits (and __traits)
On 30/08/13 23:06, Ali Çehreli wrote: How about allSatisfy: http://dlang.org/phobos/std_typetuple.html#.allSatisfy I'll have a look at that, thanks :-) Here's what I came up with, for now. It should probably be extended with further tests on the characteristics of the various member functions but it seems to be sufficient for now: template isGraph(G) { static if (!__traits(hasMember, G, directed) || !__traits(hasMember, G, edge) || !__traits(hasMember, G, edgeCount) || !__traits(hasMember, G, vertexCount) || !__traits(hasMember, G, isEdge) || !__traits(hasMember, G, edgeID) || !__traits(hasMember, G, addEdge) || !__traits(hasMember, G, degreeIn) || !__traits(hasMember, G, degreeOut) || !__traits(hasMember, G, incidentEdgesIn) || !__traits(hasMember, G, incidentEdgesOut) || !__traits(hasMember, G, neighboursIn) || !__traits(hasMember, G, neighboursOut)) { enum bool isGraph = false; } else static if (!isBoolean!(typeof(G.directed))) { enum bool isGraph = false; } else static if (G.directed (__traits(hasMember, G, degree) || __traits(hasMember, G, incidentEdges) || __traits(hasMember, G, neighbours))) { enum bool isGraph = false; } else static if (!G.directed (!__traits(hasMember, G, degree) || !__traits(hasMember, G, incidentEdges) || !__traits(hasMember, G, neighbours))) { enum bool isGraph = false; } else { enum bool isGraph = true; } }
Re: Introduction to traits (and __traits)
On 08/30/2013 01:57 PM, Joseph Rushton Wakeling wrote: On 30/08/13 21:40, Benjamin Thaut wrote: You need to put it into a static if, otherwise the compiler will continue semantic checks on the second part of the expression. E.g. template isGraph(G) { static if(__traits(hasMember, G, directed)) enum bool isGraph = isBoolean!(typeof(G.directed)); else enum bool isGraph = false; } Ahh, right, thanks. :-) Is there a recommended way for handling the case where there are many such members -- say about 10 or more? The static if's could become very highly nested with this approach. I suppose I could go through like this: static if(!__traits(hasMember, G, one)) enum bool isGraph = false; else static if(!__traits(hasMember, G, two)) enum bool isGraph = false; else static if ... ... else { // Now I know all the members exist and I can // start checking out their properties ... } How about allSatisfy: http://dlang.org/phobos/std_typetuple.html#.allSatisfy Ali
Re: Introduction to traits (and __traits)
On Fri, Aug 30, 2013 at 11:51:37PM +0200, bearophile wrote: Joseph Rushton Wakeling: static if (!__traits(hasMember, G, directed) || !__traits(hasMember, G, edge) || !__traits(hasMember, G, edgeCount) || !__traits(hasMember, G, vertexCount) || !__traits(hasMember, G, isEdge) || !__traits(hasMember, G, edgeID) || !__traits(hasMember, G, addEdge) || !__traits(hasMember, G, degreeIn) || !__traits(hasMember, G, degreeOut) || !__traits(hasMember, G, incidentEdgesIn) || !__traits(hasMember, G, incidentEdgesOut) || !__traits(hasMember, G, neighboursIn) || !__traits(hasMember, G, neighboursOut)) Perhaps can shorten that code writing a hasMembers helper (and I suggest to keep those names sorted): [...] Here's a first stab at a possible implementation: /* Warning: untested code */ import std.typetuple : allSatisfy; template isString(T) { // There may already be something in Phobos that does // this, but I'm too lazy to look. enum isString = is(T == string); } template hasMembers(alias T, Members...) if (allSatisfy!isString(Members)) { // Template recursion + exprTuple slicing FTW :) enum hasMembers = __traits(hasMember, T, Members[0]) hasMembers!(T, Members[1..$]); } void myFunc(G)(G graph) { static if (hasMembers!(G, directed, edge, /* ... */)) { ... } } T -- Computers shouldn't beep through the keyhole.
Re: Introduction to traits (and __traits)
Joseph Rushton Wakeling: static if (!__traits(hasMember, G, directed) || !__traits(hasMember, G, edge) || !__traits(hasMember, G, edgeCount) || !__traits(hasMember, G, vertexCount) || !__traits(hasMember, G, isEdge) || !__traits(hasMember, G, edgeID) || !__traits(hasMember, G, addEdge) || !__traits(hasMember, G, degreeIn) || !__traits(hasMember, G, degreeOut) || !__traits(hasMember, G, incidentEdgesIn) || !__traits(hasMember, G, incidentEdgesOut) || !__traits(hasMember, G, neighboursIn) || !__traits(hasMember, G, neighboursOut)) Perhaps can shorten that code writing a hasMembers helper (and I suggest to keep those names sorted): static if (hasMembers!(G, addEdge degreeIn ... vertexCount.split) { Bye, bearophile
Re: Introduction to traits (and __traits)
On 30/08/13 23:51, bearophile wrote: Perhaps can shorten that code writing a hasMembers helper (and I suggest to keep those names sorted) Nice thought, I might look into that at some point. :-)