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.

Attributes

AttributeSpecifier:
    Attribute :
    Attribute DeclarationBlock
Attribute: AlignAttribute AtAttribute DeprecatedAttribute FunctionAttributeKwd LinkageAttribute Pragma VisibilityAttribute abstract auto const final __gshared extern immutable inout override ref return scope shared static synchronized
FunctionAttributeKwd: nothrow pure
AtAttribute: @ disable @ nogc @ live Property @ safe @ system @ trusted UserDefinedAttribute
Property: @ property
DeclarationBlock: DeclDef { DeclDefsopt }

Attributes are a way to modify one or more declarations. The general forms are:

attribute declaration; // affects the declaration

attribute:     // affects all declarations until the end of
               // the current scope
  declaration;
  declaration;
  ...

attribute {    // affects all declarations in the block
  declaration;
  declaration;
  ...
}

Linkage Attribute

LinkageAttribute:
    extern ( LinkageType )
    extern ( C ++ , )
    extern ( C ++ , QualifiedIdentifier )
    extern ( C ++ , NamespaceList )
    extern ( C ++ , class )
    extern ( C ++ , struct )
LinkageType: C C ++ D Windows System Objective - C
NamespaceList: ConditionalExpression ConditionalExpression, ConditionalExpression, NamespaceList

D provides an easy way to call C functions and operating system API functions, as compatibility with both is essential. The LinkageType is case sensitive, and is meant to be extensible by the implementation (they are not keywords). C and D must be supplied, the others are what makes sense for the implementation. C++ offers limited compatibility with C++, see the Interfacing to C++ documentation for more information. Objective-C offers compatibility with Objective-C, see the Interfacing to Objective-C documentation for more information. System is the same as Windows on Windows platforms, and C on other platforms.

Implementation Note: for Win32 platforms, Windows should exist.

C function calling conventions are specified by:

extern (C):
    int foo(); // call foo() with C conventions
Note that extern(C) can be provided for all types of declarations, including struct or class, even though there is no corresponding match on the C side. In that case, the attribute is ignored. This behavior applies for nested functions and nested variables as well. However, for static member methods and static nested functions, adding extern(C) will change the calling convention, but not the mangling.

D conventions are:

extern (D):

Windows API conventions are:

extern (Windows):
    void *VirtualAlloc(
        void *lpAddress,
        uint dwSize,
        uint flAllocationType,
        uint flProtect
    );

The Windows convention is distinct from the C convention only on Win32 platforms, where it is equivalent to the stdcall convention.

Note that a lone extern keyword is used as a storage class.

C++ Namespaces

The linkage form extern (C++, QualifiedIdentifier) creates C++ declarations that reside in C++ namespaces. The QualifiedIdentifier specifies the namespaces.

extern (C++, N) { void foo(); }

refers to the C++ declaration:

namespace N { void foo(); }

and can be referred to with or without qualification:

foo();
N.foo();

Namespaces create a new named scope that is imported into its enclosing scope.

extern (C++, N) { void foo(); void bar(); }
extern (C++, M) { void foo(); }

void main()
{
    bar();   // ok
    //foo(); // error - N.foo() or M.foo() ?
    M.foo(); // ok
}

Multiple dotted identifiers in the QualifiedIdentifier create nested namespaces:

extern (C++, N.M) { extern (C++) { extern (C++, R) { void foo(); } } }
N.M.R.foo();

refers to the C++ declaration:

namespace N { namespace M { namespace R { void foo(); } } }

align Attribute

AlignAttribute:
    align
    align ( AssignExpression )

Specifies the alignment of:

  1. variables
  2. struct fields
  3. union fields
  4. class fields
  5. struct, union, and class types

align by itself sets it to the default, which matches the default member alignment of the companion C compiler.

struct S
{
  align:
    byte a;   // placed at offset 0
    int b;    // placed at offset 4
    long c;   // placed at offset 8
}
static assert(S.alignof == 8);
static assert(S.c.offsetof == 8);
static assert(S.sizeof == 16);

The AssignExpression specifies the alignment which matches the behavior of the companion C compiler when non-default alignments are used. It must be a non-negative power of 2.

A value of 1 means that no alignment is done; fields are packed together.

struct S
{
  align (1):
    byte a;   // placed at offset 0
    int b;    // placed at offset 1
    long c;   // placed at offset 5
}
static assert(S.alignof == 1);
static assert(S.c.offsetof == 5);
static assert(S.sizeof == 13);

The natural alignment of an aggregate is the maximum alignment of its fields. It can be overridden by setting the alignment outside of the aggregate.

align (2) struct S
{
  align (1):
    byte a;   // placed at offset 0
    int b;    // placed at offset 1
    long c;   // placed at offset 5
}
static assert(S.alignof == 2);
static assert(S.c.offsetof == 5);
static assert(S.sizeof == 14);

Setting the alignment of a field aligns it to that power of 2, regardless of the size of the field.

struct S
{
               byte a;  // placed at offset 0
    align (4)  byte b;  // placed at offset 4
    align (16) short c; // placed at offset 16
}
static assert(S.alignof == 16);
static assert(S.c.offsetof == 16);
static assert(S.sizeof == 32);

The AlignAttribute is reset to the default when entering a function scope or a non-anonymous struct, union, class, and restored when exiting that scope. It is not inherited from a base class.

See also: Struct Layout.

GC Compatibility

Do not align references or pointers that were allocated using NewExpression on boundaries that are not a multiple of size_t. The garbage collector assumes that pointers and references to GC allocated objects will be on size_t byte boundaries.

struct S
{
  align(1):
    byte b;
    int* p;
}

static assert(S.p.offsetof == 1);

@safe void main()
{
    S s;
    s.p = new int; // error: can't modify misaligned pointer in @safe code
}
Undefined Behavior: If any pointers and references to GC allocated objects are not aligned on size_t byte boundaries.

deprecated Attribute

DeprecatedAttribute:
    deprecated
    deprecated ( AssignExpression )

It is often necessary to deprecate a feature in a library, yet retain it for backwards compatibility. Such declarations can be marked as deprecated, which means that the compiler can be instructed to produce an error if any code refers to deprecated declarations:

deprecated
{
    void oldFoo();
}

oldFoo();   // Deprecated: function test.oldFoo is deprecated

Optionally a string literal or manifest constant can be used to provide additional information in the deprecation message.

deprecated("Don't use bar") void oldBar();
oldBar();   // Deprecated: function test.oldBar is deprecated - Don't use bar

Calling CTFE-able functions or using manifest constants is also possible.

import std.format;

enum message = format("%s and all its members are obsolete", Foobar.stringof);
deprecated(message) class Foobar {}
deprecated(format("%s is also obsolete", "This class")) class BarFoo {}

void main()
{
    auto fb = new Foobar();   // Deprecated: class test.Foobar is deprecated - Foobar
                             // and all its members are obsolete
    auto bf = new BarFoo();  // Deprecated: class test.BarFoo is deprecated - This
                             // class is also obsolete
}

Implementation Note: The compiler should have a switch specifying if deprecated should be ignored, cause a warning, or cause an error during compilation.

Visibility Attribute

VisibilityAttribute:
    export
    package
    package ( QualifiedIdentifier )
    private
    protected
    public

Visibility is an attribute that is one of private, package, protected, public, or export. They may be referred to as protection attributes in documents predating DIP22.

Visibility participates in symbol name lookup.

export Attribute

export means that a symbol can be accessed from outside the executable, shared library, or DLL. The symbol is said to be exported from where it is defined in an executable, shared library, or DLL, and imported by another executable, shared library, or DLL.

export applied to the definition of a symbol will export it. export applied to a declaration of a symbol will import it. A variable is a definition unless extern is applied to it.

export int x = 3;    // definition, exporting `x`
export int y;        // definition, exporting `y`
export extern int z; // declaration, importing `z`

export __gshared h = 3;        // definition, exporting `h`
export __gshared i;            // definition, exporting `i`
export extern __gshared int j; // declaration, importing `j`

A function with a body is a definition, without a body is a declaration.

export void f() { }  // definition, exporting `f`
export void g();     // declaration, importing `g`

In Windows terminology, dllexport means exporting a symbol from a DLL, and dllimport means a DLL or executable is importing a symbol from a DLL.

package Attribute

package extends private so that package members can be accessed from code in other modules that are in the same package. If no identifier is provided, this applies to the innermost package only, or defaults to private if a module is not nested in a package.

package may have an optional parameter in the form of a dot-separated identifier list which is resolved as the qualified package name. The package must be either the module's parent package or one of its ancestors. If this parameter is present, the symbol will be visible in the specified package and all of its descendants.

private Attribute

Symbols with private visibility can only be accessed from within the same module. Private member functions are implicitly final and cannot be overridden.

protected Attribute

protected only applies inside classes (and templates as they can be mixed in) and means that a symbol can only be seen by members of the same module, or by a derived class. If accessing a protected instance member through a derived class member function, that member can only be accessed for the object instance which can be implicitly cast to the same type as ‘this’. protected module members are illegal.

public Attribute

public means that any code within the executable can see the member. It is the default visibility attribute.

Mutability Attributes

const Attribute

The const type qualifier changes the type of the declared symbol from T to const(T), where T is the type specified (or inferred) for the introduced symbol in the absence of const.

const int foo = 7;
static assert(is(typeof(foo) == const(int)));

const double bar = foo + 6;
static assert(is(typeof(bar) == const(double)));
class C
{
    const void foo();
    const
    {
        void bar();
    }
    void baz() const;
}
pragma(msg, typeof(C.foo)); // const void()
pragma(msg, typeof(C.bar)); // const void()
pragma(msg, typeof(C.baz)); // const void()

static assert(is(typeof(C.foo) == typeof(C.bar)) &&
              is(typeof(C.bar) == typeof(C.baz)));

See also: Methods Returning a Qualified Type.

immutable Attribute

The immutable attribute modifies the type from T to immutable(T), the same way as const does. See:

inout Attribute

The inout attribute modifies the type from T to inout(T), the same way as const does.

Shared Storage Attributes

shared Attribute

See shared.

__gshared Attribute

By default, non-immutable global declarations reside in thread local storage. When a global variable is marked with the __gshared attribute, its value is shared across all threads.

int foo;            // Each thread has its own exclusive copy of foo.
__gshared int bar;  // bar is shared by all threads.

__gshared may also be applied to member variables and local variables. In these cases, __gshared is equivalent to static, except that the variable is shared by all threads rather than being thread local.

class Foo
{
    __gshared int bar;
}

int foo()
{
    __gshared int bar = 0;
    return bar++; // Not thread safe.
}

Warning: Unlike the shared attribute, __gshared provides no safeguards against data races or other multi-threaded synchronization issues. It is the responsibility of the programmer to ensure that access to variables marked __gshared is synchronized correctly.

__gshared is disallowed in @safe code.

@synchronized Attribute

See Synchronized Classes.

@disable Attribute

A reference to a declaration marked with the @disable attribute causes a compile time error. This can be used to explicitly disallow certain operations or overloads at compile time rather than relying on generating a runtime error.

@disable void foo() { }
void main() { foo(); /* error, foo is disabled */ }

@disable this(); inside a struct disallows default construction.

Disabling a struct copy constructor makes the struct not copyable.

@safe, @trusted, and @system Attribute

See Function Safety.

Function Attributes

@nogc Attribute

See No-GC Functions.

@property Attribute

See Property Functions.

nothrow Attribute

See Nothrow Functions.

pure Attribute

See Pure Functions.

ref Attribute

See ref Storage Class.

return Attribute

static Attribute

The static attribute applies to types, functions and data. static is ignored when applied to other declarations.

Inside an aggregate type, a static declaration does not apply to a particular instance of an object, but to the type of the object. In other words, it means there is no this reference.

class Foo
{
    static int x;
    static int bar() { return x; }
    int foobar() { return 7; }
}

Foo.x = 6; // no instance needed
assert(Foo.bar() == 6);
//Foo.foobar(); // error, no instance of Foo

Foo f = new Foo;
assert(f.bar() == 6);
assert(f.foobar() == 7);

Static methods are never virtual.

Static data has one instance per thread, not one per object.

A static nested function or type cannot access variables in the parent scope.

Inside a function, a static local variable persists after the function returns.

Static does not have the additional C meaning of being local to a file. Use the private attribute in D to achieve that. For example:

module foo;
int x = 3;         // x is global
private int y = 4; // y is local to module foo

auto Attribute

The auto attribute is used when there are no other attributes and type inference is desired.

auto i = 6.8;   // declare i as a double

For functions, the auto attribute means return type inference. See Auto Functions.

scope Attribute

The scope attribute signifies a variable's pointer values will not escape the scope that the variable is declared in.

If the variable has a type that does not contain any indirections, the scope attribute is ignored.

When applied to a global variable, scope is also ignored, since there is no scope larger than global scope that pointers could escape to.

scope int* x; // scope ignored, global variable

void main()
{
    // scope static int* x;  // cannot be both scope and static
    scope float y;           // scope ignored, no indirections
    scope int[2] z;          // scope ignored, static array is value type
    scope int[] w;           // scope dynamic array
}

When applied to a local variable with a type that has indirections, its value may not be assigned to a variable with longer lifetime:

Other operations implicitly assigning them to variables with longer lifetime are also disallowed:

The scope attribute is part of the variable declaration, not the type, and it only applies to the first level of indirection. For example, it is impossible to declare a variable as a dynamic array of scope pointers, because scope only applies to the .ptr of the array itself, not its elements. scope affects various types as follows:

Type of local variableWhat scope applies to
Any Basic Data Typenothing
Pointer T*the pointer value
Dynamic Array T[]the .ptr to the elements
Static Array T[n]each element T
Associative Array K[V]the pointer to the implementation defined structure
struct or unioneach of its member variables
function pointerthe pointer value
delegateboth the .funcptr and .ptr (closure context) pointer values
class or interfacethe class reference
enumthe base type
struct S
{
    string str; // note: string = immutable(char)[]
    string* strPtr;
}

string escape(scope S s, scope S* sPtr, scope string[2] sarray, scope string[] darray)
{
    return s.str;        // invalid, scope applies to struct members
    return *s.strPtr;    // valid, scope struct member is dereferenced
    return sPtr.str;     // valid, struct pointer is dereferenced
    return *sPtr.strPtr; // valid, two pointers are dereferenced
    return sarray[0];    // invalid, scope applies to static array elements
    return sarray[1];    // invalid, ditto
    return darray[0];    // valid, scope applies to array pointer, not elements
}

Scope Values

A "scope value" is the value of a scope variable, or a generated value pointing to stack allocated memory. Such values are generated by slicing a static array or creating a pointer to a variable that is (or may be) allocated on the stack:

The variadic parameter from Typesafe Variadic Functions is also a scope value, since the arguments are passed on the stack.

When a local variable is assigned a scope value, it is inferred scope, even when the variable has an explicit type and does not use the auto keyword.

@safe:
ref int[2] identity(return ref int[2] x) {return x;}

int* escape(int[2] y, scope int* z)
{
    int x;

    auto  xPtr  = &x;            // inferred `scope int*`
    int[] yArr  = identity(y)[]; // inferred `scope int[]`
    int*  zCopy = z;             // inferred `scope int*`

    return zCopy; // error
}

void variadic(int[] a...)
{
    int[] x = a; // inferred `scope int[]`
}

void main()
{
    variadic(1, 2, 3);
}
struct S
{
    int x;

    // this method may be called on a stack-allocated instance of S
    void f()
    {
        int* p = &x; // inferred `scope int* p`
        int* q = &this.x; // equivalent
    }
}

Scope Parameters are treated the same as scope local variables, except that returning them is allowed when the function has Function Attribute Inference. In that case, they are inferred as Return Scope Parameters.

scope Class Instances

When used to allocate a class instance directly, a scope variable signifies the RAII (Resource Acquisition Is Initialization) protocol. This means that the destructor for an object is automatically called when the reference to it goes out of scope. The destructor is called even if the scope is exited via a thrown exception, thus scope is used to guarantee cleanup.

When a class is constructed with new and assigned to a local scope variable, it may be allocated on the stack and permitted in a @nogc context.

If there is more than one scope class variable going out of scope at the same point, then the destructors are called in the reverse order that the variables were constructed.

Assignment to a scope variable with class type, other than initialization, is not allowed, because that would complicate proper destruction of the variable.

import core.stdc.stdio : puts;

class C
{
    ~this() @nogc { puts(__FUNCTION__); }
}

void main() @nogc
{
    {
        scope c0 = new C(); // allocated on the stack
        scope c1 = new C();

        //c1 = c0; // Error: cannot rebind scope variables

        // destructor of `c1` and `c0` are called here in that order
    }
    puts("bye");
}

OOP Attributes

abstract Attribute

An abstract class must be overridden by a derived class. Declaring an abstract member function makes the class abstract.

final Attribute

override Attribute

See Virtual Functions.

@mustuse Attribute

The @mustuse attribute is a compiler-recognized UDA defined in the D runtime module core.attribute.

An expression is considered to be discarded if and only if either of the following is true:

It is a compile-time error to discard an expression if all of the following are true:

"Assignment expression" means either a simple assignment expression or an assignment operator expression.

"Increment expression" means a UnaryExpression or PostfixExpression whose operator is ++.

"Decrement expression" means a UnaryExpression or PostfixExpression whose operator is --.

It is a compile-time error to attach @mustuse to a function declaration or to any aggregate declaration other than a struct or union declaration. The purpose of this rule is to reserve such usage for possible future expansion.

User-Defined Attributes

UserDefinedAttribute:
    @ ( TemplateArgumentList )
    @ TemplateSingleArgument
    @ Identifier ( NamedArgumentListopt )
    @ TemplateInstance
    @ TemplateInstance ( NamedArgumentListopt )

User-Defined Attributes (UDA) are compile-time annotations that can be attached to a declaration. These attributes can then be queried, extracted, and manipulated at compile time. There is no runtime component to them.

A user-defined attribute is defined using:
@(3) int a; // value argument
@("string", 7) int b; // multiple values

// using compile-time constant
enum val = 3;
@val int a2; // has same attribute as `a`

enum Foo;
@Foo int c; // type name attribute

struct Bar
{
    int x;
}
@Bar() int d; // type instance
@Bar(3) int e; // type instance using initializer

For e, the attribute is an instance of struct Bar which is statically initialized using its argument.

If there are multiple UDAs in scope for a declaration, they are concatenated:

@(1)
{
    @(2) int a;         // has UDAs (1, 2)
    @("string") int b;  // has UDAs (1, "string")
}

A function parameter can have a UDA:

void f(@(3) int p);

__traits(getAttributes)

UDAs can be extracted into a compile-time sequence using __traits:

@('c') string s;
pragma(msg, __traits(getAttributes, s)); // prints tuple('c')

If there are no user-defined attributes for the symbol, an empty sequence is returned. The result can be used just like any compile-time sequence - it can be indexed, passed as template parameters, etc.

enum e = 7;
@("hello") struct SSS { }
@(3)
{
    @(4) @e @SSS int foo;
}

alias TP = __traits(getAttributes, foo);

pragma(msg, TP); // prints tuple(3, 4, 7, (SSS))
pragma(msg, TP[2]); // prints 7

Any types in the sequence can be used to declare things:

TP[3] a; // a is declared as an SSS

The attribute of the type name is not the same as the attribute of the variable:

pragma(msg, __traits(getAttributes, a)); // prints tuple()
pragma(msg, __traits(getAttributes, typeof(a))); // prints tuple("hello")

Usage

Of course, the real value of UDAs is to be able to create user-defined types with specific values. Having attribute values of basic types does not scale.

Whether the attributes are values or types is up to the user, and whether later attributes accumulate or override earlier ones is also up to how the user interprets them.

Templates

If a UDA is attached to a template declaration, then it will be automatically attached to all direct members of instances of that template. If any of those members are templates themselves, this rule applies recursively:

@("foo") template Outer(T)
{
    struct S
    {
        int x;
    }
    int y;
    void fun() {}
    @("bar") template Inner(U)
    {
        int z;
    }
}

pragma(msg, __traits(getAttributes, Outer!int.S));
// prints tuple("foo")
pragma(msg, __traits(getAttributes, Outer!int.S.x));
// prints tuple()
pragma(msg, __traits(getAttributes, Outer!int.y));
// prints tuple("foo")
pragma(msg, __traits(getAttributes, Outer!int.fun));
// prints tuple("foo")
pragma(msg, __traits(getAttributes, Outer!int.Inner));
// prints tuple("foo", "bar")
pragma(msg, __traits(getAttributes, Outer!int.Inner!int.z));
// prints tuple("foo", "bar")

UDAs cannot be attached to template parameters.

Properties
Pragmas