Attributes - D Programming Language

Menu

- Learn
- Documentation
  - Language Reference
  - Library Reference
  - Command-line Reference
  - Feature Overview
  - Articles
- Downloads
- Packages
- Community
  - Blog
  - Orgs using D
  - Twitter
  - Forums
  - IRC
  - Community Discord
  - Wiki
  - GitHub
  - Issues
  - Get involved
  - Contributors
  - Foundation
  - Security Team
  - Donate
  - Sponsors
- Resources
  - Tour
  - Books
  - Tutorials
  - Tools
  - Editors
  - IDEs
  - run.dlang.io
  - 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.

# Attributes

Contents

1. Linkage Attribute
2. align Attribute
   1. GC Compatibility
3. deprecated Attribute
4. Visibility Attribute
   1. export Attribute
5. const Attribute
6. immutable Attribute
7. inout Attribute
8. shared Attribute
9. __gshared Attribute
10. @disable Attribute
11. @safe, @trusted, and @system Attribute
12. @nogc Attribute
13. @property Attribute
14. nothrow Attribute
15. pure Attribute
16. ref Attribute
17. return Attribute
18. override Attribute
19. static Attribute
20. auto Attribute
21. scope Attribute
    1. scope variables with class type
22. abstract Attribute
23. final Attribute
24. @mustuse Attribute
25. User-Defined 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 declaration 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(); }

    bar();   // ok
    foo();   // error - N.foo() or M.foo() ?
    M.foo(); // ok

Multiple 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 {}
    auto f = new Foobar();   // Deprecated: class test.Foobar is deprecated - Foobar
         // and all its members are obsolete
    deprecated(format("%s is also obsolete", "This class")) class BarFoo {}
    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:
        private
        package
        package ( QualifiedIdentifier )
        protected
        public
        export

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.

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

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 anscestors. If this optional parameter is present, the symbol will be visible in the specified package and all of its descendants.

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 means that any code within the executable can see the member. It is the default visibility attribute.

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

    export int x = 3;    // definition, exporting `x`
    export int y;        // definition, exporting `y`
    export extern int z; // declaration, importing `z`
    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.

## const Attribute

The const attribute 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)));

## immutable Attribute

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

- immutable storage class
- immutable type qualifier

## inout Attribute

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

## shared Attribute

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

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

Unlike the 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.

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

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

## return Attribute

See Return Ref Parameters.

## override Attribute

See Virtual Functions.

## 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()
    {
        static int* x;  // scope ignored, global variable
        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:

- Variables outside the Scope Statement that the variable is declared in
- Variables declared before the scope variable, since local variables are destructed in the reverse order that they are declared in
- __gshared or static variables

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

- Returning a scope variable from a function
- Assigning a scope variable to a non-scope parameter by calling a function
- Putting a scope variable in an array literal

The scope attribute is part of the variable declaration, not of 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 variable | What scope applies to
--- | ---
Any Basic Data Type | nothing
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 union | each of its member variables
function pointer | the pointer value
delegate | both the .funcptr and .ptr (closure context) pointer values
class or interface | the class reference
enum | the 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
    }

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:

- A function parameter
- A local variable
- A struct member accessed through the implicit this parameter
- The return value of a Ref Function

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[]`
    }

    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 variables with class type

When used on variables with a class type, scope 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.

    class C {}

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

            c1 = c0; // not allowed

            // destructor of `c1` and `c0` are called here in that order
        }
    }

## abstract Attribute

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

## final Attribute

- A class can be declared final to prevent subclassing.
- A class method can be declared final to prevent a derived class overriding it.
- Interfaces can define final methods.

## @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 the top-level Expression in an ExpressionStatement, or
- it is the AssignExpression on the left-hand side of the comma in a CommaExpression.

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

- it is not an assignment expression, an increment expression, or a decrement expression; and
- its type is a struct or union type whose declaration is annotated with @mustuse.

"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:
        @ ( ArgumentList )
        @ Identifier
        @ Identifier ( ArgumentListopt )
        @ TemplateInstance
        @ TemplateInstance ( ArgumentListopt )

User-Defined Attributes (UDA) are compile-time expressions 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 looks like:

    @(3) int a;

    @("string", 7) int b;

    enum Foo;
    @Foo int c;

    struct Bar
    {
        int x;
    }

    @Bar(3) int d;

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")
    }

UDAs can be extracted into an expression tuple 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 tuple is returned. The expression tuple can be turned into a manipulatable tuple:

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

    alias TP = __traits(getAttributes, foo);

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

Of course the tuple types 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, typeof(a))); // prints tuple("hello")

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. The attribute tuples can be manipulated like any other tuple, and can be passed as the argument list to a template.

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.

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
Copyright © 1999-2023 by the D Language Foundation | Page generated by Ddoc on Sat Apr 1 13:10:00 2023