Re: Introduction to traits (and __traits)

2013-08-30 Thread Benjamin Thaut

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)

2013-08-30 Thread 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


Re: Introduction to traits (and __traits)

2013-08-30 Thread Joseph Rushton Wakeling

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)

2013-08-30 Thread Joseph Rushton Wakeling

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)

2013-08-30 Thread Ali Çehreli

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)

2013-08-30 Thread H. S. Teoh
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)

2013-08-30 Thread bearophile

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)

2013-08-30 Thread Joseph Rushton Wakeling

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. :-)