Traits - D Programming Language

Menu

- Learn
- Documentation
  - Language Reference
  - Library Reference
  - Command-line Reference
  - Feature Overview
  - Articles
- Downloads
- Packages
- Community
  - Blog
  - Orgs using D
  - Twitter
  - Calendar
  - Forums
  - IRC
  - Wiki
  - GitHub
  - Issues
  - Get involved
  - Contributors
  - Foundation
  - Donate
  - Sponsors
- Resources
  - Tour
  - Books
  - Tutorials
  - Tools
  - Editors
  - IDEs
  - Visual D
  - Acknowledgments
  - D Style
  - Glossary
  - Sitemap

Search
Report a bug
If you spot a problem with this page, click here to create a Bugzilla issue.
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 a local clone.

# Traits

Contents

1. isArithmetic
2. isFloating
3. isIntegral
4. isScalar
5. isUnsigned
6. isStaticArray
7. isAssociativeArray
8. isAbstractClass
9. isFinalClass
10. isPOD
11. isNested
12. isFuture
13. isDeprecated
14. isDisabled
15. isVirtualFunction
16. isVirtualMethod
17. isAbstractFunction
18. isFinalFunction
19. isOverrideFunction
20. isStaticFunction
21. isRef
22. isTemplate
23. isReturnOnStack
24. hasMember
25. identifier
26. getAliasThis
27. getAttributes
28. getFunctionVariadicStyle
29. getFunctionAttributes
30. getLinkage
31. getMember
32. getOverloads
33. getParameterStorageClasses
34. getPointerBitmap
35. getProtection
36. getVirtualFunctions
37. getVirtualMethods
38. getUnitTests
39. parent
40. classInstanceSize
41. getVirtualIndex
42. allMembers
43. derivedMembers
44. isSame
45. compiles

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
        isFuture
        isDeprecated
        isFloating
        isIntegral
        isScalar
        isStaticArray
        isUnsigned
        isDisabled
        isVirtualFunction
        isVirtualMethod
        isAbstractFunction
        isFinalFunction
        isStaticFunction
        isOverrideFunction
        isTemplate
        isRef
        isOut
        isLazy
        isReturnOnStack
        hasMember
        identifier
        getAliasThis
        getAttributes
        getFunctionAttributes
        getFunctionVariadicStyle
        getLinkage
        getMember
        getOverloads
        getParameterStorageClasses
        getPointerBitmap
        getProtection
        getVirtualFunctions
        getVirtualMethods
        getUnitTests
        parent
        classInstanceSize
        getVirtualIndex
        allMembers
        derivedMembers
        isSame
        compiles

    TraitsArguments:
        TraitsArgument
        TraitsArgument , TraitsArguments

    TraitsArgument:
        AssignExpression
        Type

## 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.

## isFuture

Takes one argument. It returns true if the argument is a symbol marked with the @future keyword, otherwise false. Currently, only functions and variable declarations have support for the @future keyword.

## isDeprecated

Takes one argument. It returns true if the argument is a symbol marked with the deprecated keyword, otherwise false.

## isDisabled

Takes one argument and returns true if it's a function declaration marked with @disable.

    struct Foo
    {
        @disable void foo();
        void bar(){}
    }

    static assert(__traits(isDisabled, Foo.foo));
    static assert(!__traits(isDisabled, Foo.bar));

For any other declaration even if @disable is a syntactically valid attribute false is returned because the annotation has no effect.

    @disable struct Bar{}

    static assert(!__traits(isDisabled, Bar));

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

## isTemplate

Takes one argument. If that argument is a template then true is returned, otherwise false.

    void foo(T)(){}
    static assert(__traits(isTemplate,foo));
    static assert(!__traits(isTemplate,foo!int()));
    static assert(!__traits(isTemplate,"string"));

## isReturnOnStack

Takes one argument which must either be a function symbol, function literal, a delegate, or a function pointer. It returns a bool which is true if the return value of the function is returned on the stack via a pointer to it passed as a hidden extra parameter to the function.

    struct S { int[20] a; }
    int test1();
    S test2();

    static assert(__traits(isReturnOnStack, test1) == false);
    static assert(__traits(isReturnOnStack, test2) == true);

Implementation Defined: This is determined by the function ABI calling convention in use, which is often complex.
Best Practices: This has applications in:

1. Returning values in registers is often faster, so this can be used as a check on a hot function to ensure it is using the fastest method.
2. When using inline assembly to correctly call a function.
3. Testing that the compiler does this correctly is normally hackish and awkward, this enables efficient, direct, and simple testing.

## 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.

    import std.stdio;

    int var = 123;
    pragma(msg, typeof(var));                       // int
    pragma(msg, typeof(__traits(identifier, var))); // string
    writeln(var);                                   // 123
    writeln(__traits(identifier, var));             // "var"

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

## getFunctionVariadicStyle

Takes one argument which must either be a function symbol, or a type that is a function, delegate or a function pointer. It returns a string identifying the kind of variadic arguments that are supported.

getFunctionVariadicStyle
result | kind | access | example
--- | --- | --- | ---
"none" | not a variadic function |  | void foo();
"argptr" | D style variadic function | _argptr and _arguments | void bar(...)
"stdarg" | C style variadic function | core.stdc.stdarg | extern (C) void abc(int, ...)
"typesafe" | typesafe variadic function | array on stack | void def(int[] ...)

    import core.stdc.stdarg;

    void novar() {}
    extern(C) void cstyle(int, ...) {}
    extern(C++) void cppstyle(int, ...) {}
    void dstyle(...) {}
    void typesafe(int[]...) {}

    static assert(__traits(getFunctionVariadicStyle, novar) == "none");
    static assert(__traits(getFunctionVariadicStyle, cstyle) == "stdarg");
    static assert(__traits(getFunctionVariadicStyle, cppstyle) == "stdarg");
    static assert(__traits(getFunctionVariadicStyle, dstyle) == "argptr");
    static assert(__traits(getFunctionVariadicStyle, typesafe) == "typesafe");

    static assert(__traits(getFunctionVariadicStyle, (int[] a...) {}) == "typesafe");
    static assert(__traits(getFunctionVariadicStyle, typeof(cstyle)) == "stdarg");

## getFunctionAttributes

Takes one argument which must either be a function symbol, function literal, or a function pointer. It returns a string tuple of all the attributes of that function excluding any user-defined attributes (UDAs can be retrieved with the getAttributes trait). If no attributes exist it will return an empty tuple.

Note: The order of the attributes in the returned tuple is implementation-defined and should not be relied upon.

A list of currently supported attributes are:

- pure, nothrow, @nogc, @property, @system, @trusted, @safe, and ref

Note: ref is a function attribute even though it applies to the return type.

Additionally the following attributes are only valid for non-static member functions:

- const, immutable, inout, shared

For example:

    int sum(int x, int y) pure nothrow { return x + y; }

    // prints ("pure", "nothrow", "@system")
    pragma(msg, __traits(getFunctionAttributes, sum));

    struct S
    {
        void test() const @system { }
    }

    // prints ("const", "@system")
    pragma(msg, __traits(getFunctionAttributes, S.test));

Note that some attributes can be inferred. For example:

    // prints ("pure", "nothrow", "@nogc", "@trusted")
    pragma(msg, __traits(getFunctionAttributes, (int x) @trusted { return x * 2; }));

## getLinkage

Takes one argument, which is a declaration symbol, or the type of a function, delegate, or pointer to function. Returns a string representing the LinkageAttribute of the declaration. The string is one of:

- "D"
- "C"
- "C++"
- "Windows"
- "Pascal"
- "Objective-C"
- "System"

    extern (C) int fooc();
    alias aliasc = fooc;

    static assert(__traits(getLinkage, fooc) == "C");
    static assert(__traits(getLinkage, aliasc) == "C");

## 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

## getParameterStorageClasses

Takes two arguments. The first must either be a function symbol, or a type that is a function, delegate or a function pointer. The second is an integer identifying which parameter, where the first parameter is 0. It returns a tuple of strings representing the storage classes of that parameter.

    ref int foo(return ref const int* p, scope int* a, out int b, lazy int c);

    static assert(__traits(getParameterStorageClasses, foo, 0)[0] == "return");
    static assert(__traits(getParameterStorageClasses, foo, 0)[1] == "ref");

    static assert(__traits(getParameterStorageClasses, foo, 1)[0] == "scope");
    static assert(__traits(getParameterStorageClasses, foo, 2)[0] == "out");
    static assert(__traits(getParameterStorageClasses, typeof(&foo), 3)[0] == "lazy");

## getPointerBitmap

The argument is a type. The result is an array of size_t describing the memory used by an instance of the given type.

The first element of the array is the size of the type (for classes it is the classInstanceSize).

The following elements describe the locations of GC managed pointers within the memory occupied by an instance of the type. For type T, there are T.sizeof / size_t.sizeof possible pointers represented by the bits of the array values.

This array can be used by a precise GC to avoid false pointers.

    class C
    {
        // implicit virtual function table pointer not marked
        // implicit monitor field not marked, usually managed manually
        C next;
        size_t sz;
        void* p;
        void function () fn; // not a GC managed pointer
    }

    struct S
    {
        size_t val1;
        void* p;
        C c;
        byte[] arr;          // { length, ptr }
        void delegate () dg; // { context, func }
    }

    static assert (__traits(getPointerBitmap, C) == [6*size_t.sizeof, 0b010100]);
    static assert (__traits(getPointerBitmap, S) == [7*size_t.sizeof, 0b0110110]);

## 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, CTFE 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.

If the two arguments are both lambda functions (or aliases to lambda functions), then they are compared for equality. For the comparison to be computed correctly, the following conditions must be met for both lambda functions:

1. The lambda function arguments must not have a template instantiation as an explicit argument type. Any other argument types (basic, user-defined, template) are supported.
2. The lambda function body must contain a single expression (no return statement) which contains only numeric values, manifest constants, enum values, function arguments and function calls. If the expression contains local variables or return statements, the function is considered incomparable.

If these constraints aren't fulfilled, the function is considered incomparable and isSame returns false.

    int f() { return 2; }
    void test(alias pred)()
    {
        // f() from main is a different function from top-level f()
        static assert(!__traits(isSame, (int a) => a + f(), pred));
    }

    void main()
    {
        static assert(__traits(isSame, (a, b) => a + b, (c, d) => c + d));
        static assert(__traits(isSame, a => ++a, b => ++b));
        static assert(!__traits(isSame, (int a, int b) => a + b, (a, b) => a + b));
        static assert(__traits(isSame, (a, b) => a + b + 10, (c, d) => c + d + 10));

        // lambdas accessing local variables are considered incomparable
        int b;
        static assert(!__traits(isSame, a => a + b, a => a + b));

        // lambdas calling other functions are comparable
        int f() { return 3;}
        static assert(__traits(isSame, a => a + f(), a => a + f()));
        test!((int a) => a + f())();

        class A
        {
            int a;
            this(int a)
            {
                this.a = a;
            }
        }

        class B
        {
            int a;
            this(int a)
            {
                this.a = a;
            }
        }

        static assert(__traits(isSame, (A a) => ++a.a, (A b) => ++b.a));
        // lambdas with different data types are considered incomparable,
        // even if the memory layout is the same
        static assert(!__traits(isSame, (A a) => ++a.a, (B a) => ++a.a));
    }

## 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:

- Giving better error messages inside generic code than the sometimes hard to follow compiler ones.
- Doing a finer grained specialization than template partial specialization allows for.

Conditional Compilation
Error Handling
Copyright © 1999-2018 by the D Language Foundation | Page generated by Ddoc on Tue Apr 17 10:35:35 2018