D Programming Language 2.0

- Forum
- Wiki
- Search
- Downloads
- Home

Last update Tue Jul 19 00:15:57 2011

# 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
        isFloating
        isIntegral
        isScalar
        isStaticArray
        isUnsigned
        isVirtualFunction
        isAbstractFunction
        isFinalFunction
        isStaticFunction
        isRef
        isOut
        isLazy
        hasMember
        identifier
        getMember
        getOverloads
        getVirtualFunctions
        parent
        classInstanceSize
        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;
      writefln(__traits(isArithmetic, int));
      writefln(__traits(isArithmetic, i, i+1, int));
      writefln(__traits(isArithmetic));
      writefln(__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;
      writefln(__traits(isAbstractClass, C));
      writefln(__traits(isAbstractClass, c, C));
      writefln(__traits(isAbstractClass));
      writefln(__traits(isAbstractClass, int*));
    }

Prints:

    true
    true
    false
    false

## isFinalClass

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

## isVirtualFunction

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

    import std.stdio;

    struct S {
      void bar() { }
    }

    class C {
      void bar() { }
    }

    void main() {
      writefln(__traits(isVirtualFunction, C.bar));  // true
      writefln(__traits(isVirtualFunction, 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() {
      writefln(__traits(isAbstractFunction, C.bar));   // false
      writefln(__traits(isAbstractFunction, S.bar));   // false
      writefln(__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() {
      writefln(__traits(isFinalFunction, C.bar));	  // false
      writefln(__traits(isFinalFunction, S.bar));	  // false
      writefln(__traits(isFinalFunction, C.foo));	  // true
      writefln(__traits(isFinalFunction, FC.foo));  // true
    }

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

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

## identifier

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

## 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;
      writefln(__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 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 an array 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"))
        writefln(typeid(typeof(t)));

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

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

Prints:

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

## getVirtualFunctions

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 an array of the virtual 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(getVirtualFunctions, D, "foo"))
        writefln(typeid(typeof(t)));

      alias typeof(__traits(getVirtualFunctions, D, "foo")) b;
      foreach (t; b)
        writefln(typeid(t));

      auto i = __traits(getVirtualFunctions, d, "foo")[1](1);
      writefln(i);
    }

Prints:

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

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

## 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 a = __traits(allMembers, D);
      writefln(a);
      // _ctor,_dtor,foo,print,toString,toHash,opCmp,opEquals

      auto b = [ __traits(allMembers, D) ];
      writefln(b);
      // [_ctor,_dtor,foo,print,toString,toHash,opCmp,opEquals]
    }

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);
      writefln(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() {
      writefln(__traits(isSame, foo, foo)); // true
      writefln(__traits(isSame, foo, bar)); // false
      writefln(__traits(isSame, foo, S));   // false
      writefln(__traits(isSame, S, S));     // true
      writefln(__traits(isSame, std, S));   // false
      writefln(__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() {
      writefln(__traits(compiles));                      // false
      writefln(__traits(compiles, foo));                 // true
      writefln(__traits(compiles, foo + 1));             // true
      writefln(__traits(compiles, &foo + 1));            // false
      writefln(__traits(compiles, typeof(1)));           // true
      writefln(__traits(compiles, S.s1));                // true
      writefln(__traits(compiles, S.s3));                // false
      writefln(__traits(compiles, 1,2,3,int,long,std));  // true
      writefln(__traits(compiles, 3[1]));                // false
      writefln(__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.

Forums | Comments | D | Search | Downloads | Home
Copyright © 1999-2011 by Digital Mars ®, All Rights Reserved | Page generated by Ddoc.