Improve this page Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using local clone. Page wiki View or edit the community-maintained wiki page associated with this page.

Traits

Traits are extensions to the language to enable programs, at compile time, to get at information internal to the compiler. This is also known as compile time reflection. It is done as a special, easily extended syntax (similar to Pragmas) so that new capabilities can be added as required.

TraitsExpression:
    __traits ( TraitsKeyword , TraitsArguments )

TraitsKeyword:
    isAbstractClass
    isArithmetic
    isAssociativeArray
    isFinalClass
    isPOD
    isNested
    isFloating
    isIntegral
    isScalar
    isStaticArray
    isUnsigned
    isVirtualFunction
    isVirtualMethod
    isAbstractFunction
    isFinalFunction
    isStaticFunction
    isOverrideFunction
    isRef
    isOut
    isLazy
    hasMember
    identifier
    getAliasThis
    getAttributes
    getMember
    getOverloads
    getProtection
    getVirtualFunctions
    getVirtualMethods
    getUnitTests
    parent
    classInstanceSize
    getVirtualIndex
    allMembers
    derivedMembers
    isSame
    compiles

TraitsArguments:
    TraitsArgument
    TraitsArgument , TraitsArguments

TraitsArgument:
    AssignExpression
    Type

Additionally special keywords are provided for debugging purposes:

SpecialKeyword:
    __FILE__
    __MODULE__
    __LINE__
    __FUNCTION__
    __PRETTY_FUNCTION__

isArithmetic

If the arguments are all either types that are arithmetic types, or expressions that are typed as arithmetic types, then true is returned. Otherwise, false is returned. If there are no arguments, false is returned.

import std.stdio;

void main() {
  int i;
  writeln(__traits(isArithmetic, int));
  writeln(__traits(isArithmetic, i, i+1, int));
  writeln(__traits(isArithmetic));
  writeln(__traits(isArithmetic, int*));
}

Prints:

true
true
false
false

isFloating

Works like isArithmetic, except it's for floating point types (including imaginary and complex types).

isIntegral

Works like isArithmetic, except it's for integral types (including character types).

isScalar

Works like isArithmetic, except it's for scalar types.

isUnsigned

Works like isArithmetic, except it's for unsigned types.

isStaticArray

Works like isArithmetic, except it's for static array types.

isAssociativeArray

Works like isArithmetic, except it's for associative array types.

isAbstractClass

If the arguments are all either types that are abstract classes, or expressions that are typed as abstract classes, then true is returned. Otherwise, false is returned. If there are no arguments, false is returned.

import std.stdio;

abstract class C { int foo(); }

void main() {
  C c;
  writeln(__traits(isAbstractClass, C));
  writeln(__traits(isAbstractClass, c, C));
  writeln(__traits(isAbstractClass));
  writeln(__traits(isAbstractClass, int*));
}

Prints:

true
true
false
false

isFinalClass

Works like isAbstractClass, except it's for final classes.

isPOD

Takes one argument, which must be a type. It returns true if the type is a POD type, otherwise false.

isNested

Takes one argument. It returns true if the argument is a nested type which internally stores a context pointer, otherwise it returns false. Nested types can be classes, structs, and functions.

isVirtualFunction

The same as isVirtualMethod, except that final functions that don't override anything return true.

isVirtualMethod

Takes one argument. If that argument is a virtual function, true is returned, otherwise false. Final functions that don't override anything return false.

import std.stdio;

struct S {
  void bar() { }
}

class C {
  void bar() { }
}

void main() {
  writeln(__traits(isVirtualMethod, C.bar));  // true
  writeln(__traits(isVirtualMethod, S.bar));  // false
}

isAbstractFunction

Takes one argument. If that argument is an abstract function, true is returned, otherwise false.

import std.stdio;

struct S {
  void bar() { }
}

class C {
  void bar() { }
}

class AC {
  abstract void foo();
}

void main() {
  writeln(__traits(isAbstractFunction, C.bar));   // false
  writeln(__traits(isAbstractFunction, S.bar));   // false
  writeln(__traits(isAbstractFunction, AC.foo));  // true
}

isFinalFunction

Takes one argument. If that argument is a final function, true is returned, otherwise false.

import std.stdio;

struct S {
  void bar() { }
}

class C {
  void bar() { }
  final void foo();
}

final class FC {
  void foo();
}

void main() {
  writeln(__traits(isFinalFunction, C.bar));	  // false
  writeln(__traits(isFinalFunction, S.bar));	  // false
  writeln(__traits(isFinalFunction, C.foo));	  // true
  writeln(__traits(isFinalFunction, FC.foo));  // true
}

isOverrideFunction

Takes one argument. If that argument is a function marked with override, true is returned, otherwise false.

import std.stdio;

class Base {
  void foo() { }
}

class Foo : Base
{
  override void foo() { }
  void bar() { }
}

void main() {
  writeln(__traits(isOverrideFunction, Base.foo));	// false
  writeln(__traits(isOverrideFunction, Foo.foo));	// true
  writeln(__traits(isOverrideFunction, Foo.bar));	// false
}

isStaticFunction

Takes one argument. If that argument is a static function, meaning it has no context pointer, true is returned, otherwise false.

isRef, isOut, isLazy

Takes one argument. If that argument is a declaration, true is returned if it is ref, out, or lazy, otherwise false.

void fooref(ref int x) {
  static assert(__traits(isRef, x));
  static assert(!__traits(isOut, x));
  static assert(!__traits(isLazy, x));
}

void fooout(out int x) {
  static assert(!__traits(isRef, x));
  static assert(__traits(isOut, x));
  static assert(!__traits(isLazy, x));
}

void foolazy(lazy int x) {
  static assert(!__traits(isRef, x));
  static assert(!__traits(isOut, x));
  static assert(__traits(isLazy, x));
}

hasMember

The first argument is a type that has members, or is an expression of a type that has members. The second argument is a string. If the string is a valid property of the type, true is returned, otherwise false.

import std.stdio;

struct S {
  int m;
}

void main() {
  S s;

  writeln(__traits(hasMember, S, "m")); // true
  writeln(__traits(hasMember, s, "m")); // true
  writeln(__traits(hasMember, S, "y")); // false
  writeln(__traits(hasMember, int, "sizeof")); // true
}

identifier

Takes one argument, a symbol. Returns the identifier for that symbol as a string literal.

getAliasThis

Takes one argument, a symbol of aggregate type. If the given aggregate type has alias this, returns a list of alias this names, by a tuple of strings. Otherwise returns an empty tuple.

getAttributes

Takes one argument, a symbol. Returns a tuple of all attached user defined attributes. If no UDA's exist it will return an empty tuple.

For more information, see: User Defined Attributes

@(3) int a;
@("string", 7) int b;

enum Foo;
@Foo int c;

pragma(msg, __traits(getAttributes, a));
pragma(msg, __traits(getAttributes, b));
pragma(msg, __traits(getAttributes, c));

Prints:

tuple(3)
tuple("string", 7)
tuple((Foo))

getMember

Takes two arguments, the second must be a string. The result is an expression formed from the first argument, followed by a ‘.’, followed by the second argument as an identifier.

import std.stdio;

struct S {
  int mx;
  static int my;
}

void main() {
  S s;

  __traits(getMember, s, "mx") = 1;  // same as s.mx=1;
  writeln(__traits(getMember, s, "m" ~ "x")); // 1

  __traits(getMember, S, "mx") = 1;  // error, no this for S.mx
  __traits(getMember, S, "my") = 2;  // ok
}

getOverloads

The first argument is an aggregate (e.g. struct/class/module). The second argument is a string that matches the name of one of the functions in that aggregate. The result is a tuple of all the overloads of that function.

import std.stdio;

class D {
  this() { }
  ~this() { }
  void foo() { }
  int foo(int) { return 2; }
}

void main() {
  D d = new D();

  foreach (t; __traits(getOverloads, D, "foo"))
    writeln(typeid(typeof(t)));

  alias b = typeof(__traits(getOverloads, D, "foo"));
  foreach (t; b)
    writeln(typeid(t));

  auto i = __traits(getOverloads, d, "foo")[1](1);
  writeln(i);
}

Prints:

void()
int()
void()
int()
2

getProtection

The argument is a symbol. The result is a string giving its protection level: "public", "private", "protected", "export", or "package".

import std.stdio;

class D {
  export void foo() { }
  public int bar;
}

void main() {
  D d = new D();

  auto i = __traits(getProtection, d.foo);
  writeln(i);

  auto j = __traits(getProtection, d.bar);
  writeln(j);
}

Prints:

export
public

getVirtualFunctions

The same as getVirtualMethods, except that final functions that do not override anything are included.

getVirtualMethods

The first argument is a class type or an expression of class type. The second argument is a string that matches the name of one of the functions of that class. The result is a tuple of the virtual overloads of that function. It does not include final functions that do not override anything.

import std.stdio;

class D {
  this() { }
  ~this() { }
  void foo() { }
  int foo(int) { return 2; }
}

void main() {
  D d = new D();

  foreach (t; __traits(getVirtualMethods, D, "foo"))
    writeln(typeid(typeof(t)));

  alias b = typeof(__traits(getVirtualMethods, D, "foo"));
  foreach (t; b)
    writeln(typeid(t));

  auto i = __traits(getVirtualMethods, d, "foo")[1](1);
  writeln(i);
}

Prints:

void()
int()
void()
int()
2

getUnitTests

Takes one argument, a symbol of an aggregate (e.g. struct/class/module). The result is a tuple of all the unit test functions of that aggregate. The functions returned are like normal nested static functions, CTEF will work and UDA's will be accessible.

Note:

The -unittest flag needs to be passed to the compiler. If the flag is not passed __traits(getUnitTests) will always return an empty tuple.

module foo;

import core.runtime;
import std.stdio;

struct name { string name; }

class Foo {
  unittest {
    writeln("foo.Foo.unittest");
  }
}

@name("foo") unittest {
  writeln("foo.unittest");
}

template Tuple (T...)
{
  alias Tuple = T;
}

shared static this()
{
  // Override the default unit test runner to do nothing. After that, "main" will
  // be called.
  Runtime.moduleUnitTester = { return true; };
}

void main() {
  writeln("start main");

  alias tests = Tuple!(__traits(getUnitTests, foo));
  static assert(tests.length == 1);

  alias attributes = Tuple!(__traits(getAttributes, tests[0]));
  static assert(attributes.length == 1);

  foreach (test; tests)
    test();

  foreach (test; __traits(getUnitTests, Foo))
    test();
}

By default, the above will print:

start main
foo.unittest
foo.Foo.unittest

parent

Takes a single argument which must evaluate to a symbol. The result is the symbol that is the parent of it.

classInstanceSize

Takes a single argument, which must evaluate to either a class type or an expression of class type. The result is of type size_t, and the value is the number of bytes in the runtime instance of the class type. It is based on the static type of a class, not the polymorphic type.

getVirtualIndex

Takes a single argument which must evaluate to a function. The result is a ptrdiff_t containing the index of that function within the vtable of the parent type. If the function passed in is final and does not override a virtual function, -1 is returned instead.

allMembers

Takes a single argument, which must evaluate to either a type or an expression of type. A tuple of string literals is returned, each of which is the name of a member of that type combined with all of the members of the base classes (if the type is a class). No name is repeated. Builtin properties are not included.

import std.stdio;

class D {
  this() { }
  ~this() { }
  void foo() { }
  int foo(int) { return 0; }
}

void main() {
  auto b = [ __traits(allMembers, D) ];
  writeln(b);
  // ["__ctor", "__dtor", "foo", "toString", "toHash", "opCmp", "opEquals", "Monitor", "factory"]
}

The order in which the strings appear in the result is not defined.

derivedMembers

Takes a single argument, which must evaluate to either a type or an expression of type. A tuple of string literals is returned, each of which is the name of a member of that type. No name is repeated. Base class member names are not included. Builtin properties are not included.

import std.stdio;

class D {
  this() { }
  ~this() { }
  void foo() { }
  int foo(int) { return 0; }
}

void main() {
  auto a = [__traits(derivedMembers, D)];
  writeln(a);    // ["__ctor", "__dtor", "foo"]
}

The order in which the strings appear in the result is not defined.

isSame

Takes two arguments and returns bool true if they are the same symbol, false if not.

import std.stdio;

struct S { }

int foo();
int bar();

void main() {
  writeln(__traits(isSame, foo, foo)); // true
  writeln(__traits(isSame, foo, bar)); // false
  writeln(__traits(isSame, foo, S));   // false
  writeln(__traits(isSame, S, S));     // true
  writeln(__traits(isSame, std, S));   // false
  writeln(__traits(isSame, std, std)); // true
}

If the two arguments are expressions made up of literals or enums that evaluate to the same value, true is returned.

compiles

Returns a bool true if all of the arguments compile (are semantically correct). The arguments can be symbols, types, or expressions that are syntactically correct. The arguments cannot be statements or declarations.

If there are no arguments, the result is false.

import std.stdio;

struct S {
  static int s1;
  int s2;
}

int foo();
int bar();

void main() {
  writeln(__traits(compiles));                      // false
  writeln(__traits(compiles, foo));                 // true
  writeln(__traits(compiles, foo + 1));             // true
  writeln(__traits(compiles, &foo + 1));            // false
  writeln(__traits(compiles, typeof(1)));           // true
  writeln(__traits(compiles, S.s1));                // true
  writeln(__traits(compiles, S.s3));                // false
  writeln(__traits(compiles, 1,2,3,int,long,std));  // true
  writeln(__traits(compiles, 3[1]));                // false
  writeln(__traits(compiles, 1,2,3,int,long,3[1])); // false
}

This is useful for:

Special Keywords

__FILE__ and __LINE__ expand to the source file name and line number at the point of instantiation.

__MODULE__ expands to the module name at the point of instantiation.

__FUNCTION__ expands to the fully qualified name of the function at the point of instantiation.

__PRETTY_FUNCTION__ is similar to __FUNCTION__, but also expands the function return type, its parameter types, and its attributes.

Example usage:

module test;
import std.stdio;

void test(string file = __FILE__, size_t line = __LINE__, string mod = __MODULE__,
          string func = __FUNCTION__, string pretty = __PRETTY_FUNCTION__)
{
    writefln("file: '%s', line: '%s', module: '%s',\nfunction: '%s', pretty function: '%s'",
             file, line, mod, func, pretty);
}

int main(string[] args)
{
    test();
    return 0;
}

This will output:

file: 'test.d', line: '13', module: 'test',
function: 'test.main', pretty function: 'int test.main(string[] args)'
Forums | Comments | Search | Downloads | Home