Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 165 additions & 0 deletions std/traits.d
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
* $(LREF hasElaborateDestructor)
* $(LREF hasIndirections)
* $(LREF hasMember)
* $(LREF isStaticMember)
* $(LREF hasNested)
* $(LREF hasUnsharedAliasing)
* $(LREF InterfacesTuple)
Expand Down Expand Up @@ -3340,6 +3341,170 @@ enum hasMember(T, string name) = __traits(hasMember, T, name);
static assert(hasMember!(S, "foo"));
}

/++
Whether the symbol represented by the string, member, is a static member of
T.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs params and returns

+/
template isStaticMember(T, string member)
if (__traits(hasMember, T, member))
{
import std.meta : Alias;
alias sym = Alias!(__traits(getMember, T, member));

static if (__traits(getOverloads, T, member).length == 0)
enum bool isStaticMember = __traits(compiles, &sym);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use compiles instead of is(typeof(&sym))?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that it matters in this case, but there are subtle differences between the two, and I've been advised in the past to favor __traits(compiles, ...). If I understand correctly, the main difference is that __traits(compiles, ...) actually checks for compilation, whereas is(typeof(...)) just checks that the type exists (e.g. there was a discussion on it here with Don: https://issues.dlang.org/show_bug.cgi?id=8339 ). __traits(compiles, ...) is also more explicit about what you're doing. So, I generally try to use __traits(compiles, ...) instead of is(typeof(...)). I confess though that I don't understand the subtleties well enough to know when it really matters.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels like a weird recommendation. I wonder if there is a compiler workload difference?
I have a very poor feel for what things the compiler does quickly, and which are high-impact on compile time.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Andrei was the one who recommended the traits option to me, so you can probably ask him

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TurkeyMan there is almost no difference.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In cases where this does hit your compile times you need a high n.
In such cases template instanciation cost will shadow everything else.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does 'accurate' mean? I've seen a bunch of weird recommendations emerging... they're not written anywhere. Are people just supposed to know?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TurkeyMan It's more or less folk knowledge that's passed around. I don't think it's documented anywhere other than various forum threads. That said, it is definitely better to use __traits(compiles).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's more or less folk knowledge that's passed around.

Right, and that's absolutely not okay! We're meant to be attracting new users. The meta experience is D's main offering, and new users should be able to get working and feel powerful with as little friction as possible. "Oh, yeah that obvious thing to type isn't actually what you do, you need to do this awkward unintuitive thing instead" is not something that's okay to say to new users.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not claiming it's obvious or ideal 😉 Just letting you know how things are.

else
enum bool isStaticMember = __traits(isStaticFunction, sym);
}

///
unittest
{
static struct S
{
static void sf() {}
void f() {}

static int si;
int i;
}

static assert( isStaticMember!(S, "sf"));
static assert(!isStaticMember!(S, "f"));

static assert( isStaticMember!(S, "si"));
static assert(!isStaticMember!(S, "i"));

static assert(!__traits(compiles, isStaticMember!(S, "hello")));
}

unittest
{
static struct S
{
enum X = 10;
enum Y
{
i = 10
}
struct S {}
class C {}

static int sx = 0;
__gshared int gx = 0;

Y y;
static Y sy;

static void f() {}
static void f2() pure nothrow @nogc @safe {}

shared void g() {}

static void function() fp;
__gshared void function() gfp;
void function() fpm;

void delegate() dm;
static void delegate() sd;

void m() {}
final void m2() const pure nothrow @nogc @safe {}

inout(int) iom() inout { return 10; }
static inout(int) iosf(inout int x) { return x; }

@property int p() { return 10; }
static @property int sp() { return 10; }
}

static class C
{
enum X = 10;
enum Y
{
i = 10
}
struct S {}
class C {}

static int sx = 0;
__gshared int gx = 0;

Y y;
static Y sy;

static void f() {}
static void f2() pure nothrow @nogc @safe {}

shared void g() {}

static void function() fp;
__gshared void function() gfp;
void function() fpm;

void delegate() dm;
static void delegate() sd;

void m() {}
final void m2() const pure nothrow @nogc @safe {}

inout(int) iom() inout { return 10; }
static inout(int) iosf(inout int x) { return x; }

@property int p() { return 10; }
static @property int sp() { return 10; }
}

static assert(!isStaticMember!(S, "X"));
static assert(!isStaticMember!(S, "Y"));
static assert(!__traits(compiles, isStaticMember!(S, "Y.i")));
static assert(!isStaticMember!(S, "S"));
static assert(!isStaticMember!(S, "C"));
static assert( isStaticMember!(S, "sx"));
static assert( isStaticMember!(S, "gx"));
static assert(!isStaticMember!(S, "y"));
static assert( isStaticMember!(S, "sy"));
static assert( isStaticMember!(S, "f"));
static assert( isStaticMember!(S, "f2"));
static assert(!isStaticMember!(S, "dm"));
static assert( isStaticMember!(S, "sd"));
static assert(!isStaticMember!(S, "g"));
static assert( isStaticMember!(S, "fp"));
static assert( isStaticMember!(S, "gfp"));
static assert(!isStaticMember!(S, "fpm"));
static assert(!isStaticMember!(S, "m"));
static assert(!isStaticMember!(S, "m2"));
static assert(!isStaticMember!(S, "iom"));
static assert( isStaticMember!(S, "iosf"));
static assert(!isStaticMember!(S, "p"));
static assert( isStaticMember!(S, "sp"));

static assert(!isStaticMember!(C, "X"));
static assert(!isStaticMember!(C, "Y"));
static assert(!__traits(compiles, isStaticMember!(C, "Y.i")));
static assert(!isStaticMember!(C, "S"));
static assert(!isStaticMember!(C, "C"));
static assert( isStaticMember!(C, "sx"));
static assert( isStaticMember!(C, "gx"));
static assert(!isStaticMember!(C, "y"));
static assert( isStaticMember!(C, "sy"));
static assert( isStaticMember!(C, "f"));
static assert( isStaticMember!(C, "f2"));
static assert(!isStaticMember!(S, "dm"));
static assert( isStaticMember!(S, "sd"));
static assert(!isStaticMember!(C, "g"));
static assert( isStaticMember!(C, "fp"));
static assert( isStaticMember!(C, "gfp"));
static assert(!isStaticMember!(C, "fpm"));
static assert(!isStaticMember!(C, "m"));
static assert(!isStaticMember!(C, "m2"));
static assert(!isStaticMember!(C, "iom"));
static assert( isStaticMember!(C, "iosf"));
static assert(!isStaticMember!(C, "p"));
static assert( isStaticMember!(C, "sp"));
}

/**
Retrieves the members of an enumerated type $(D enum E).

Expand Down