Skip to content
Merged
Show file tree
Hide file tree
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
14 changes: 14 additions & 0 deletions changelog/std-traits-hasStaticMember.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Added `std.traits.hasStaticMember` to check whether a symbol is a static member of a type.
Copy link
Contributor

Choose a reason for hiding this comment

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

@andralex while the current changelog parser is very forgiving, we should probably make a decision on the format:

  • (A) title (can be multiple lines) - empty line - description
  • (B) title (one line) - empty line (optional) - description

(A) is implemented as dlang/tools#220
(B) is how our parser works currently.
Personally I am quite happy with closing the PR and agreeing that a title can't be more than one line (doesn't make much sense anyways).

Copy link
Member

Choose a reason for hiding this comment

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

I'll let @CyberShadow decide, thanks!

Copy link
Member

Choose a reason for hiding this comment

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

I don't see any deciding arguments one way or another.

I think enforcing that the second line is blank would be good to avoid accidental ambiguity, and would follow formatting for git commit messages.

Copy link
Member

Choose a reason for hiding this comment

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

Suggestion: start with a more restrictive policy then relax it as experience develops. The other way is much more difficult, as we've all learned the hard way :).

Copy link
Contributor

Choose a reason for hiding this comment

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

I think enforcing that the second line is blank would be good to avoid accidental ambiguity,
Suggestion: start with a more restrictive policy then relax it as experience develops.

@sprinkle131313 as we seem to have reached a consensus here, would you be so kind to insert an empty line after the title?

Copy link
Member

Choose a reason for hiding this comment

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

@wilzbach how do we use that nice relatively new feature of github allowing others to amend someone's pull request?

Copy link
Member

Choose a reason for hiding this comment

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

The PR author needs to opt in, which it doesn't look like they've done here.

Copy link
Contributor

Choose a reason for hiding this comment

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

https://wiki.dlang.org/Guidelines_for_maintainers#Write_access_to_PRs

It's enabled here:

image

Anyways we put this into the reminder message of the DLang-Bot:
dlang/dlang-bot#44

Copy link
Member

Choose a reason for hiding this comment

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

It's enabled here:

Oh, oops, I was looking in the wrong place.


-------
import std.traits : hasStaticMember;

struct S
{
static int staticVar;
int nonstaticVar;
}

assert( hasStaticMember!(S, "staticVar"));
assert(!hasStaticMember!(S, "nonstaticVar"));
-------
177 changes: 177 additions & 0 deletions std/traits.d
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
* $(LREF hasElaborateDestructor)
* $(LREF hasIndirections)
* $(LREF hasMember)
* $(LREF hasStaticMember)
* $(LREF hasNested)
* $(LREF hasUnsharedAliasing)
* $(LREF InterfacesTuple)
Expand Down Expand Up @@ -3553,6 +3554,182 @@ enum hasMember(T, string name) = __traits(hasMember, T, name);
static assert(hasMember!(S, "foo"));
}

/**
* Whether the symbol represented by the string, member, exists and is a static member of T.
*
* Params:
* T = Type containing symbol $(D member).
* member = Name of symbol to test that resides in $(D T).
*
* Returns:
* $(D true) iff $(D member) exists and is static.
*/
template hasStaticMember(T, string member)
{
static 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 hasStaticMember = __traits(compiles, &sym);
else
enum bool hasStaticMember = __traits(isStaticFunction, sym);
}
else
{
enum bool hasStaticMember = false;
}
}

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

static int si;
int i;
}

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

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

static assert(!hasStaticMember!(S, "hello"));
}

@safe 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;
static inout(int) iosf(inout int x);

@property int p();
static @property int sp();
}

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);

@property int p() { return 10; }
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't define a body when you don't call it as it will lead to coverage errors ;-)

Copy link
Contributor Author

@skl131313 skl131313 Mar 4, 2017

Choose a reason for hiding this comment

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

Those ones caused link errors in the test build if they aren't there.

For reference, the related error'd build:

https://circleci.com/gh/dlang/phobos/2050

generated/linux/debug/64/unittest/libphobos2-ut.so: undefined reference to `_D3std6traits18__unittestL3606_69FZ1C1gMOFZv'
generated/linux/debug/64/unittest/libphobos2-ut.so: undefined reference to `_D3std6traits18__unittestL3606_69FZ1C1pMFNdZi'
generated/linux/debug/64/unittest/libphobos2-ut.so: undefined reference to `_D3std6traits18__unittestL3606_69FZ1C3iomMNgFZNgi'
generated/linux/debug/64/unittest/libphobos2-ut.so: undefined reference to `_D3std6traits18__unittestL3606_69FZ1C1mMFZv'

static @property int sp();
}

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

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

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

Expand Down