$(DDOC $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE ) $(SPEC_S Classes, $(DDOC_BLANKLINE ) $(HEADERNAV_TOC $(HEADERNAV_ITEM access_control, Access Control) $(HEADERNAV_ITEM super_class, Super Class) $(HEADERNAV_SUBITEMS fields, Fields, $(HEADERNAV_ITEM field_properties, Field Properties) ) $(HEADERNAV_SUBITEMS class_properties, Class Properties, $(HEADERNAV_ITEM hidden-fields, Accessing Hidden Fields) ) $(HEADERNAV_SUBITEMS member-functions, Member Functions (a.k.a. Methods), $(HEADERNAV_ITEM objc-member-functions, Objective-C linkage) ) $(HEADERNAV_ITEM synchronized-classes, Synchronized Classes) $(HEADERNAV_SUBITEMS constructors, Constructors, $(HEADERNAV_ITEM base-construction, Base Class Construction) $(HEADERNAV_ITEM delegating-constructors, Delegating Constructors) $(HEADERNAV_ITEM implicit-base-construction, Implicit Base Class Construction) $(HEADERNAV_ITEM class-instantiation, Class Instantiation) $(HEADERNAV_ITEM constructor-attributes, Constructor Attributes) $(HEADERNAV_ITEM field-init, Field initialization inside a constructor) ) $(HEADERNAV_ITEM destructors, Destructors) $(HEADERNAV_ITEM static-constructor, Static Constructors) $(HEADERNAV_ITEM static-destructor, Static Destructors) $(HEADERNAV_ITEM shared_static_constructors, Shared Static Constructors) $(HEADERNAV_ITEM shared_static_destructors, Shared Static Destructors) $(HEADERNAV_ITEM invariants, Class Invariants) $(HEADERNAV_ITEM auto, Scope Classes) $(HEADERNAV_ITEM abstract, Abstract Classes) $(HEADERNAV_ITEM final, Final Classes) $(HEADERNAV_SUBITEMS nested, Nested Classes, $(HEADERNAV_ITEM static-nested, Static Nested Classes) $(HEADERNAV_ITEM nested-context, Context Pointer) $(HEADERNAV_ITEM nested-explicit, Explicit Instantiation) $(HEADERNAV_ITEM outer-property, outer Property) $(HEADERNAV_ITEM anonymous, Anonymous Nested Classes) ) $(HEADERNAV_ITEM const-class, $(ARGS Const, Immutable and Shared Classes)) ) $(DDOC_BLANKLINE ) $(P The object-oriented features of D all come from classes. The class hierarchy has as its root the class Object. Object defines a minimum level of functionality that each derived class has, and a default implementation for that functionality. ) $(DDOC_BLANKLINE ) $(P Classes are programmer defined types. Support for classes are what make D an object oriented language, giving it encapsulation, inheritance, and polymorphism. D classes support the single inheritance paradigm, extended by adding support for interfaces. Class objects are instantiated by reference only. ) $(DDOC_BLANKLINE ) $(P A class can be exported, which means its name and all its non-private members are exposed externally to the DLL or EXE. ) $(DDOC_BLANKLINE ) $(P A class declaration is defined: ) $(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME ClassDeclaration): $(D class) $(GLINK_LEX Identifier) $(D ;) $(D class) $(GLINK_LEX Identifier) $(GLINK BaseClassList)$(OPT ) $(GLINK2 struct, AggregateBody) $(GLINK2 template, ClassTemplateDeclaration) $(DDOC_BLANKLINE ) $(GNAME BaseClassList): $(D :) $(GLINK SuperClassOrInterface) $(D :) $(GLINK SuperClassOrInterface) $(D ,) $(GLINK Interfaces) $(DDOC_BLANKLINE ) $(GNAME SuperClassOrInterface): $(GLINK2 type, BasicType) $(DDOC_BLANKLINE ) $(GNAME Interfaces): $(GLINK Interface) $(GLINK Interface) $(D ,) $(GSELF Interfaces) $(DDOC_BLANKLINE ) $(GNAME Interface): $(GLINK2 type, BasicType) ) $(DDOC_BLANKLINE ) $(P A class consists of:) $(DDOC_BLANKLINE ) $(COMMENT list of notable components, not exhaustive) $(UL $(LI a $(RELATIVE_LINK2 super_class, super class)) $(LI $(DDLINK spec/interface, Interfaces, interfaces) $(LI dynamic fields) $(LI $(DDSUBLINK spec/attribute, static, static) fields) $(LI $(RELATIVE_LINK2 nested, nested classes)) $(LI $(RELATIVE_LINK2 member-functions, member functions)) $(UL $(LI static member functions) $(LI $(DDSUBLINK spec/function, virtual-functions, Virtual Functions)) $(LI $(RELATIVE_LINK2 constructors, Constructors)) $(LI $(RELATIVE_LINK2 destructors, Destructors)) $(LI $(RELATIVE_LINK2 invariants, Class Invariants)) $(LI $(DDLINK spec/operatoroverloading, Operator Overloading, Operator Overloading)) ) $(LI other declarations (see $(GLINK2 module, DeclDef))) ) ) $(DDOC_BLANKLINE ) $(P A class is defined:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) Foo { ... members ... } ) $(DDOC_BLANKLINE ) $(PANEL $(NOTE Unlike C++, there is no trailing $(D ;) after the closing $(D }) of the class definition. It is also not possible to declare a variable var inline:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) Foo { } var; ) $(DDOC_BLANKLINE ) Instead, use: $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) Foo { } Foo var; ) ) $(DDOC_BLANKLINE )

$(LNAME2 access_control, Access Control)

$(DDOC_BLANKLINE ) $(P Access to class members is controlled using $(DDSUBLINK spec/attribute, visibility_attributes, visibility attributes). The default visibility attribute is $(D public). ) $(DDOC_BLANKLINE )

$(LNAME2 super_class, Super Class)

$(DDOC_BLANKLINE ) $(P All classes inherit from a super class. If one is not specified, a class inherits from $(REF1 Object, object). Object forms the root of the D class inheritance hierarchy. ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) A { } $(D_COMMENT // A inherits from Object )$(D_KEYWORD class) B : A { } $(D_COMMENT // B inherits from A )) $(DDOC_BLANKLINE ) $(P Multiple class inheritance is not supported, however a class can inherit from multiple $(DDLINK spec/interface, Interfaces, interfaces). If a super class is declared, it must come before any interfaces. Commas are used to separate inherited types.) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 fields, Fields)

$(DDOC_BLANKLINE ) $(P Class members are always accessed with the . operator. ) $(DDOC_BLANKLINE ) $(P Members of a base class can be accessed by prepending the name of the base class followed by a dot:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) A { $(D_KEYWORD int) a; $(D_KEYWORD int) a2;} $(D_KEYWORD class) B : A { $(D_KEYWORD int) a; } $(D_KEYWORD void) foo(B b) { b.a = 3; $(D_COMMENT // accesses field B.a ) b.a2 = 4; $(D_COMMENT // accesses field A.a2 ) b.A.a = 5; $(D_COMMENT // accesses field A.a )} ) $(DDOC_BLANKLINE ) $(P The D compiler is free to rearrange the order of fields in a class to optimally pack them in an implementation-defined manner. Consider the fields much like the local variables in a function - the compiler assigns some to registers and shuffles others around all to get the optimal stack frame layout. This frees the code designer to organize the fields in a manner that makes the code more readable rather than being forced to organize it according to machine optimization rules. Explicit control of field layout is provided by struct/union types, not classes. ) $(DDOC_BLANKLINE ) $(P Fields of extern(Objective-C) classes have a dynamic offset. That means that the base class can change (add or remove instance variables) without the subclasses needing to recompile or relink. ) $(DDOC_BLANKLINE )

$(LNAME2 field_properties, Field Properties)

$(DDOC_BLANKLINE ) $(P The $(D .offsetof) property gives the offset in bytes of the field from the beginning of the class instantiation. .offsetof is not available for fields of extern(Objective-C) classes due to their fields having a dynamic offset. ) $(DDOC_BLANKLINE )

$(LNAME2 class_properties, Class Properties)

$(DDOC_BLANKLINE ) $(P The $(D .tupleof) property is an $(DDSUBLINK spec/template, homogeneous_sequences, lvalue sequence) of all the non-static fields in the class, excluding the hidden fields and the fields in the base class.) $(P The order of the fields in the tuple matches the order in which the fields are declared.) $(NOTE .tupleof is not available for extern(Objective-C) classes due to their fields having a dynamic offset. ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD class) Foo { $(D_KEYWORD int) x; $(D_KEYWORD long) y; } $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD __traits)(identifier, Foo.tupleof[0]) == $(D_STRING "x")); $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)($(D_KEYWORD typeof)(Foo.tupleof)[1] == $(D_KEYWORD long))); $(D_KEYWORD void) main() { $(D_KEYWORD import) std.stdio; $(D_KEYWORD auto) foo = $(D_KEYWORD new) Foo; foo.tupleof[0] = 1; $(D_COMMENT // set foo.x to 1 ) foo.tupleof[1] = 2; $(D_COMMENT // set foo.y to 2 ) $(D_KEYWORD foreach) ($(D_KEYWORD ref) x; foo.tupleof) x++; $(D_KEYWORD assert)(foo.x == 2); $(D_KEYWORD assert)(foo.y == 3); $(D_KEYWORD auto) bar = $(D_KEYWORD new) Foo; bar.tupleof = foo.tupleof; $(D_COMMENT // copy fields ) $(D_KEYWORD assert)(bar.x == 2); $(D_KEYWORD assert)(bar.y == 3); } ) ) $(DDOC_BLANKLINE )

$(LNAME2 hidden-fields, Accessing Hidden Fields)

$(DDOC_BLANKLINE ) $(P The $(RELATIVE_LINK2 outer-property, .outer property) for a nested class instance provides either the parent class instance, or the parent function's context pointer when there is no parent class.) $(DDOC_BLANKLINE ) $(P The properties $(D .__vptr) and $(D .__monitor) give access to the class object's vtbl[] and monitor, respectively, but should not be used in user code. ) $(DDOC_BLANKLINE )

$(LNAME2 member-functions, Member Functions (a.k.a. Methods))

$(DDOC_BLANKLINE ) $(P Non-static member functions have an extra hidden parameter called $(DDSUBLINK spec/expression, this, this) through which the class object's other members can be accessed. ) $(DDOC_BLANKLINE ) $(P Non-static member functions can have, in addition to the usual $(GLINK2 function, FunctionAttribute)s, the attributes $(D const), $(D immutable), $(D shared), $(D inout), $(D scope) or $(D return scope). These attributes apply to the hidden $(I this) parameter. ) $(SPEC_RUNNABLE_EXAMPLE_FAIL $(D_CODE $(D_KEYWORD class) C { $(D_KEYWORD int) a; $(D_KEYWORD void) foo() $(D_KEYWORD const) { a = 3; $(D_COMMENT // error, 'this' is const ) } $(D_KEYWORD void) foo() $(D_KEYWORD immutable) { a = 3; $(D_COMMENT // error, 'this' is immutable ) } C bar() @safe $(D_KEYWORD scope) { $(D_KEYWORD return) $(D_KEYWORD this); $(D_COMMENT // error, 'this' is scope ) } } ) ) $(DDOC_BLANKLINE )

$(LNAME2 objc-member-functions, Objective-C linkage)

$(DDOC_BLANKLINE ) $(P Static member functions with Objective-C linkage also have an extra hidden parameter called $(I this) through which the class object's other members can be accessed. ) $(DDOC_BLANKLINE ) $(P Member functions with Objective-C linkage have an additional hidden, anonymous, parameter which is the selector the function was called with. ) $(DDOC_BLANKLINE ) $(P Static member functions with Objective-C linkage are placed in a hidden nested metaclass as non-static member functions. ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 synchronized-classes, Synchronized Classes)

$(DDOC_BLANKLINE ) $(P All member functions of synchronized classes are synchronized. A static member function is synchronized on the $(I classinfo) object for the class, which means that one monitor is used for all static member functions for that synchronized class. For non-static functions of a synchronized class, the monitor used is part of the class object. For example: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD synchronized) $(D_KEYWORD class) Foo { $(D_KEYWORD void) bar() { ...statements... } } ) $(DDOC_BLANKLINE ) $(P is equivalent to (as far as the monitors go): ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD synchronized) $(D_KEYWORD class) Foo { $(D_KEYWORD void) bar() { $(D_KEYWORD synchronized) ($(D_KEYWORD this)) { ...statements... } } } ) $(DDOC_BLANKLINE ) $(P Member functions of non-synchronized classes can be individually marked as synchronized. ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) Foo { $(D_KEYWORD synchronized) $(D_KEYWORD void) foo() { } $(D_COMMENT // foo is synchronized )} ) $(DDOC_BLANKLINE ) $(P Member fields of a synchronized class cannot be public: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD synchronized) $(D_KEYWORD class) Foo { $(D_KEYWORD int) foo; $(D_COMMENT // disallowed: public field )} $(D_KEYWORD synchronized) $(D_KEYWORD class) Bar { $(D_KEYWORD private) $(D_KEYWORD int) bar; $(D_COMMENT // ok )} ) $(DDOC_BLANKLINE ) $(P The $(D synchronized) attribute can only be applied to classes, structs cannot be marked to be synchronized.) $(DDOC_BLANKLINE )

$(LNAME2 constructors, Constructors)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME Constructor): $(D this) $(GLINK2 function, Parameters) $(GLINK2 function, MemberFunctionAttributes)$(OPT ) $(GLINK2 function, FunctionBody) $(GLINK2 template, ConstructorTemplate) ) $(DDOC_BLANKLINE ) $(P Fields are by default initialized to the $(LNAME2 class-default-initializer, default initializer) for their type (usually 0 for integer types and NAN for floating point types). If the field declaration has an optional $(GLINK2 declaration, Initializer) that will be used instead of the default. ) $(D_CODE $(D_KEYWORD class) Abc { $(D_KEYWORD int) a; $(D_COMMENT // default initializer for a is 0 ) $(D_KEYWORD long) b = 7; $(D_COMMENT // default initializer for b is 7 ) $(D_KEYWORD float) f; $(D_COMMENT // default initializer for f is NAN )} ) $(DDOC_BLANKLINE ) $(P The $(I Initializer) is evaluated at compile time.) $(DDOC_BLANKLINE ) $(P This initialization is done before any constructors are called.) $(DDOC_BLANKLINE ) $(P Constructors are defined with a function name of $(D this) and have no return value:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) Foo { $(CODE_HIGHLIGHT $(D_KEYWORD this))($(D_KEYWORD int) x) $(D_COMMENT // declare constructor for Foo ) { ... } $(CODE_HIGHLIGHT $(D_KEYWORD this))() { ... } } ) $(DDOC_BLANKLINE )

$(LNAME2 base-construction, Base Class Construction)

$(DDOC_BLANKLINE ) $(P Base class construction is done by calling the base class constructor by the name $(D super):) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) A { $(D_KEYWORD this)($(D_KEYWORD int) y) { } } $(D_KEYWORD class) B : A { $(D_KEYWORD int) j; $(D_KEYWORD this)() { ... $(CODE_HIGHLIGHT $(D_KEYWORD super))(3); $(D_COMMENT // call base constructor A.this$(LPAREN)3$(RPAREN ) ) ... } } ) $(DDOC_BLANKLINE )

$(LNAME2 delegating-constructors, Delegating Constructors)

$(DDOC_BLANKLINE ) $(P A constructor can call another constructor for the same class in order to share common initializations. This is called a $(I delegating constructor): ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) C { $(D_KEYWORD int) j; $(D_KEYWORD this)() { ... } $(D_KEYWORD this)($(D_KEYWORD int) i) { $(CODE_HIGHLIGHT $(D_KEYWORD this))(); $(D_COMMENT // delegating constructor call ) j = i; } } ) $(DDOC_BLANKLINE ) $(P The following restrictions apply:) $(DDOC_BLANKLINE ) $(OL $(LI It is illegal for constructors to mutually call each other. $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD this)() { $(D_KEYWORD this)(1); } $(D_KEYWORD this)($(D_KEYWORD int) i) { $(D_KEYWORD this)(); } $(D_COMMENT // illegal, cyclic constructor calls )) $(DDOC_BLANKLINE ) $(IMPLEMENTATION_DEFINED The compiler is not required to detect cyclic constructor calls.) $(DDOC_BLANKLINE ) $(UNDEFINED_BEHAVIOR If the program executes with cyclic constructor calls.) ) $(DDOC_BLANKLINE ) $(LI If a constructor's code contains a delegating constructor call, all possible execution paths through the constructor must make exactly one delegating constructor call: $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD this)() { a || $(D_KEYWORD super)(); } $(D_COMMENT // illegal ) $(D_KEYWORD this)() { (a) ? $(D_KEYWORD this)(1) : $(D_KEYWORD super)(); } $(D_COMMENT // ok ) $(D_KEYWORD this)() { $(D_KEYWORD for) (...) { $(D_KEYWORD super)(); $(D_COMMENT // illegal, inside loop ) } } ) ) $(DDOC_BLANKLINE ) $(LI It is illegal to refer to $(D this) implicitly or explicitly prior to making a delegating constructor call.) $(DDOC_BLANKLINE ) $(LI Delegating constructor calls cannot appear after labels.) ) $(DDOC_BLANKLINE )

$(LNAME2 implicit-base-construction, Implicit Base Class Construction)

$(DDOC_BLANKLINE ) $(P If there is no constructor for a class, but there is a constructor for the base class, a default constructor is implicitly generated with the form:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD this)() { } ) $(DDOC_BLANKLINE ) $(P If no calls to a delegating constructor or $(D super) appear in a constructor, and the base class has a nullary constructor, a call to super() is inserted at the beginning of the constructor. If that base class has a constructor that requires arguments and no nullary constructor, a matching call to super is required.) $(DDOC_BLANKLINE )

$(LNAME2 class-instantiation, Class Instantiation)

$(DDOC_BLANKLINE ) $(P Instances of class objects are created with a $(GLINK2 expression, NewExpression):) $(DDOC_BLANKLINE ) $(D_CODE A a = $(D_KEYWORD new) A(3); ) $(DDOC_BLANKLINE ) $(P A $(DDSUBLINK spec/attribute, scope-class-var, scope class instance) is allocated on the stack.) $(DDOC_BLANKLINE ) $(P The following steps happen:) $(DDOC_BLANKLINE ) $(OL $(LI Storage is allocated for the object. If this fails, rather than return $(D null), an $(LINK2 $(ROOT_DIR )library/core/exception/out_of_memory_error.html, OutOfMemoryError) is thrown. Thus, tedious checks for null references are unnecessary. ) $(DDOC_BLANKLINE ) $(LI The raw data is statically initialized using the values provided in the class definition. The pointer to the vtbl[] (the array of pointers to virtual functions) is assigned. Constructors are passed fully formed objects for which virtual functions can be called. This operation is equivalent to doing a memory copy of a static version of the object onto the newly allocated one. ) $(DDOC_BLANKLINE ) $(LI If there is a constructor defined for the class, the constructor matching the argument list is called. ) $(DDOC_BLANKLINE ) $(LI If a delegating constructor is not called, a call to the base class's default constructor is issued.) $(DDOC_BLANKLINE ) $(LI The body of the constructor is executed.) $(DDOC_BLANKLINE ) $(LI If class invariant checking is turned on, the class invariant is called at the end of the constructor. ) ) $(DDOC_BLANKLINE )

$(LNAME2 constructor-attributes, Constructor Attributes)

$(DDOC_BLANKLINE ) $(P Constructors can have one of these member function attributes: $(D const), $(D immutable), and $(D shared). Construction of qualified objects will then be restricted to the implemented qualified constructors. ) $(D_CODE $(D_KEYWORD class) C { $(D_KEYWORD this)(); $(D_COMMENT // non-shared mutable constructor )} $(D_COMMENT // create mutable object )C m = $(D_KEYWORD new) C(); $(D_COMMENT // create const object using mutable constructor )$(D_KEYWORD const) C c2 = $(D_KEYWORD new) $(D_KEYWORD const) C(); $(D_COMMENT // a mutable constructor cannot create an immutable object )$(D_COMMENT // immutable C i = new immutable C$(LPAREN)$(RPAREN ); ) $(D_COMMENT // a mutable constructor cannot create a shared object )$(D_COMMENT // shared C s = new shared C$(LPAREN)$(RPAREN ); )) $(DDOC_BLANKLINE ) $(P Constructors can be overloaded with different attributes. ) $(D_CODE $(D_KEYWORD class) C { $(D_KEYWORD this)(); $(D_COMMENT // non-shared mutable constructor ) $(D_KEYWORD this)() $(D_KEYWORD shared); $(D_COMMENT // shared mutable constructor ) $(D_KEYWORD this)() $(D_KEYWORD immutable); $(D_COMMENT // immutable constructor )} C m = $(D_KEYWORD new) C(); $(D_KEYWORD shared) s = $(D_KEYWORD new) $(D_KEYWORD shared) C(); $(D_KEYWORD immutable) i = $(D_KEYWORD new) $(D_KEYWORD immutable) C(); ) $(DDOC_BLANKLINE )

$(LNAME2 pure-constructors, Pure Constructors)

$(DDOC_BLANKLINE ) $(P If the constructor can create a unique object (e.g. if it is pure), the object can be implicitly convertible to any qualifiers. ) $(D_CODE $(D_KEYWORD class) C { $(D_KEYWORD this)() $(D_KEYWORD pure); $(D_COMMENT // Based on the definition, this creates a mutable object. But the ) $(D_COMMENT // created object cannot contain any mutable global data. ) $(D_COMMENT // Therefore the created object is unique. ) $(D_KEYWORD this)($(D_KEYWORD int)[] arr) $(D_KEYWORD immutable) $(D_KEYWORD pure); $(D_COMMENT // Based on the definition, this creates an immutable object. But ) $(D_COMMENT // the argument int[] never appears in the created object so it ) $(D_COMMENT // isn't implicitly convertible to immutable. Also, it cannot store ) $(D_COMMENT // any immutable global data. ) $(D_COMMENT // Therefore the created object is unique. )} $(D_KEYWORD immutable) i = $(D_KEYWORD new) $(D_KEYWORD immutable) C(); $(D_COMMENT // this$(LPAREN)$(RPAREN ) pure is called )$(D_KEYWORD shared) s = $(D_KEYWORD new) $(D_KEYWORD shared) C(); $(D_COMMENT // this$(LPAREN)$(RPAREN ) pure is called )C m = $(D_KEYWORD new) C([1,2,3]); $(D_COMMENT // this$(LPAREN)int[]$(RPAREN ) immutable pure is called )) $(DDOC_BLANKLINE )

$(LNAME2 field-init, Field initialization inside a constructor)

$(DDOC_BLANKLINE ) $(P In a constructor body, the first instance of field assignment is its initialization. ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) C { $(D_KEYWORD int) num; $(D_KEYWORD this)() { num = 1; $(D_COMMENT // initialization ) num = 2; $(D_COMMENT // assignment ) } } ) $(DDOC_BLANKLINE ) $(P If the field type has an $(LINK2 operatoroverloading.html#assignment, opAssign) method, it will not be used for initialization.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD struct) A { $(D_KEYWORD this)($(D_KEYWORD int) n) {} $(D_KEYWORD void) $(CODE_HIGHLIGHT opAssign)(A rhs) {} } $(D_KEYWORD class) C { A val; $(D_KEYWORD this)() { val = A(1); $(D_COMMENT // val is initialized to the value of A$(LPAREN)1$(RPAREN ) ) val = A(2); $(D_COMMENT // rewritten to val.opAssign$(LPAREN)A$(LPAREN)2$(RPAREN )$(RPAREN ) ) } } ) $(DDOC_BLANKLINE ) $(P If the field type is not mutable, multiple initialization will be rejected.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) C { $(D_KEYWORD immutable) $(D_KEYWORD int) num; $(D_KEYWORD this)() { num = 1; $(D_COMMENT // OK ) num = 2; $(D_COMMENT // Error: multiple field initialization ) } } ) $(DDOC_BLANKLINE ) $(P If the field is initialized on one path, it must be initialized on all paths.) $(D_CODE $(D_KEYWORD class) C { $(D_KEYWORD immutable) $(D_KEYWORD int) num; $(D_KEYWORD immutable) $(D_KEYWORD int) ber; $(D_KEYWORD this)($(D_KEYWORD int) i) { $(D_KEYWORD if) (i) num = 3; $(D_COMMENT // initialization ) $(D_KEYWORD else) num = 4; $(D_COMMENT // initialization ) } $(D_KEYWORD this)($(D_KEYWORD long) j) { j ? (num = 3) : (num = 4); $(D_COMMENT // ok ) j || (ber = 3); $(D_COMMENT // error, intialized on only one path ) j && (ber = 3); $(D_COMMENT // error, intialized on only one path ) } } ) $(DDOC_BLANKLINE ) $(P A field initialization may not appear in a loop or after a label.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) C { $(D_KEYWORD immutable) $(D_KEYWORD int) num; $(D_KEYWORD immutable) string str; $(D_KEYWORD this)() { $(D_KEYWORD foreach) (i; 0..2) { num = 1; $(D_COMMENT // Error: field initialization not allowed in loops ) } size_t i = 0; Label: str = $(D_STRING "hello"); $(D_COMMENT // Error: field initialization not allowed after labels ) $(D_KEYWORD if) (i++ < 2) $(D_KEYWORD goto) Label; } } ) $(DDOC_BLANKLINE ) $(P If a field's type has disabled default construction, then it must be initialized in the constructor.) $(D_CODE $(D_KEYWORD struct) S { $(D_KEYWORD int) y; @disable $(D_KEYWORD this)(); } $(D_KEYWORD class) C { S s; $(D_KEYWORD this)(S t) { s = t; } $(D_COMMENT // ok ) $(D_KEYWORD this)($(D_KEYWORD int) i) { $(D_KEYWORD this)(); } $(D_COMMENT // ok ) $(D_KEYWORD this)() { } $(D_COMMENT // error, s not initialized )} ) $(DDOC_BLANKLINE )

$(LNAME2 destructors, Destructors)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME Destructor): $(D ~ this ( )) $(GLINK2 function, MemberFunctionAttributes)$(OPT ) $(GLINK2 function, FunctionBody) ) $(DDOC_BLANKLINE ) $(P The destructor function is called when:) $(UL $(LI A live object is deleted by the garbage collector) $(LI A live $(DDSUBLINK spec/attribute, scope-class-var, scope class instance) goes out of scope) $(LI $(REF1 destroy, object) is called on the object ) ) $(P Example:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD import) std.stdio; $(D_KEYWORD class) Foo { ~$(D_KEYWORD this)() $(D_COMMENT // destructor for Foo ) { writeln($(D_STRING "dtor")); } } $(D_KEYWORD void) main() { $(D_KEYWORD auto) foo = $(D_KEYWORD new) Foo; destroy(foo); writeln($(D_STRING "end")); } ) ) $(UL $(LI Only one destructor can be declared per class, although other destructors $(DDSUBLINK spec/template-mixin, destructors, can be mixed in).) $(LI A destructor does not have any parameters or attributes.) $(LI A destructor is always virtual. ) ) $(P The destructor is expected to release any non-GC resources held by the object. ) $(DDOC_BLANKLINE ) $(P The program can explicitly call the destructor of a live object immediately with $(REF1 destroy, object). The runtime marks the object so the destructor is never called twice. ) $(DDOC_BLANKLINE ) $(P The destructor for the $(RELATIVE_LINK2 super_class, super class) automatically gets called when the destructor ends. There is no way to call the super class destructor explicitly. ) $(DDOC_BLANKLINE ) $(IMPLEMENTATION_DEFINED The garbage collector is not guaranteed to run the destructor for all unreferenced objects.) $(DDOC_BLANKLINE ) $(PANEL $(DIVC spec-boxes, $(B Important:) The order in which the garbage collector calls destructors for unreferenced objects is not specified. This means that when the garbage collector calls a destructor for an object of a class that has members which are references to garbage collected objects, those references may no longer be valid. This means that destructors cannot reference sub objects.) $(DDOC_BLANKLINE ) $(NOTE This rule does not apply to a scope class instance or an object destructed with destroy, as the destructor is not being run during a garbage collection cycle, meaning all references are valid.) ) $(DDOC_BLANKLINE ) $(P Objects referenced from the static data segment never get collected by the GC. ) $(DDOC_BLANKLINE )

$(LNAME2 static-constructor, Static Constructors)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME StaticConstructor): $(D static this ( )) $(GLINK2 function, MemberFunctionAttributes)$(OPT ) $(GLINK2 function, FunctionBody) ) $(DDOC_BLANKLINE ) $(P A static constructor is a function that performs initializations of thread local data before the $(D main()) function gets control for the main thread, and upon thread startup.) $(DDOC_BLANKLINE ) $(P Static constructors are used to initialize static class members with values that cannot be computed at compile time.) $(DDOC_BLANKLINE ) $(P Static constructors in other languages are built implicitly by using member initializers that can't be computed at compile time. The trouble with this stems from not having good control over exactly when the code is executed, for example: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) Foo { $(D_KEYWORD static) $(D_KEYWORD int) a = b + 1; $(D_KEYWORD static) $(D_KEYWORD int) b = a * 2; } ) $(DDOC_BLANKLINE ) What values do a and b end up with, what order are the initializations executed in, what are the values of a and b before the initializations are run, is this a compile error, or is this a runtime error? Additional confusion comes from it not being obvious if an initializer is static or dynamic. $(DDOC_BLANKLINE ) $(P D makes this simple. All member initializations must be determinable by the compiler at compile time, hence there is no order-of-evaluation dependency for member initializations, and it is not possible to read a value that has not been initialized. Dynamic initialization is performed by a static constructor, defined with a special syntax $(D static this()).) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) Foo { $(D_KEYWORD static) $(D_KEYWORD int) a; $(D_COMMENT // default initialized to 0 ) $(D_KEYWORD static) $(D_KEYWORD int) b = 1; $(D_KEYWORD static) $(D_KEYWORD int) c = b + a; $(D_COMMENT // error, not a constant initializer ) $(CODE_HIGHLIGHT $(D_KEYWORD static) $(D_KEYWORD this))() $(D_COMMENT // static constructor ) { a = b + 1; $(D_COMMENT // a is set to 2 ) b = a * 2; $(D_COMMENT // b is set to 4 ) } } ) $(DDOC_BLANKLINE ) $(P If $(D main()) or the thread returns normally, (does not throw an exception), the static destructor is added to the list of functions to be called on thread termination.) $(DDOC_BLANKLINE ) $(P Static constructors have empty parameter lists.) $(DDOC_BLANKLINE ) $(P Static constructors within a module are executed in the lexical order in which they appear. All the static constructors for modules that are directly or indirectly imported are executed before the static constructors for the importer. ) $(DDOC_BLANKLINE ) $(P The $(D static) in the static constructor declaration is not an attribute, it must appear immediately before the $(D this): ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) Foo { $(D_KEYWORD static) $(D_KEYWORD this)() { ... } $(D_COMMENT // a static constructor ) $(D_KEYWORD static) $(D_KEYWORD private) $(D_KEYWORD this)() { ... } $(D_COMMENT // not a static constructor ) $(D_KEYWORD static) { $(D_KEYWORD this)() { ... } $(D_COMMENT // not a static constructor ) } $(D_KEYWORD static): $(D_KEYWORD this)() { ... } $(D_COMMENT // not a static constructor )} ) $(DDOC_BLANKLINE )

$(LNAME2 static-destructor, Static Destructors)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME StaticDestructor): $(D static ~ this ( )) $(GLINK2 function, MemberFunctionAttributes)$(OPT ) $(GLINK2 function, FunctionBody) ) $(DDOC_BLANKLINE ) A static destructor is defined as a special static function with the syntax $(D static ~this()). $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) Foo { $(D_KEYWORD static) ~$(D_KEYWORD this)() $(D_COMMENT // static destructor ) { } } ) $(DDOC_BLANKLINE ) $(P A static destructor gets called on thread termination, but only if the static constructor completed successfully. Static destructors have empty parameter lists. Static destructors get called in the reverse order that the static constructors were called in. ) $(DDOC_BLANKLINE ) $(P The $(D static) in the static destructor declaration is not an attribute, it must appear immediately before the $(D ~this): ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) Foo { $(D_KEYWORD static) ~$(D_KEYWORD this)() { ... } $(D_COMMENT // a static destructor ) $(D_KEYWORD static) $(D_KEYWORD private) ~$(D_KEYWORD this)() { ... } $(D_COMMENT // not a static destructor ) $(D_KEYWORD static) { ~$(D_KEYWORD this)() { ... } $(D_COMMENT // not a static destructor ) } $(D_KEYWORD static): ~$(D_KEYWORD this)() { ... } $(D_COMMENT // not a static destructor )} ) $(DDOC_BLANKLINE )

$(LNAME2 shared_static_constructors, Shared Static Constructors)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME SharedStaticConstructor): $(D shared static this ( )) $(GLINK2 function, MemberFunctionAttributes)$(OPT ) $(GLINK2 function, FunctionBody) ) $(DDOC_BLANKLINE ) $(P Shared static constructors are executed before any $(GLINK StaticConstructor)s, and are intended for initializing any shared global data. ) $(DDOC_BLANKLINE )

$(LNAME2 shared_static_destructors, Shared Static Destructors)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME SharedStaticDestructor): $(D shared static ~ this ( )) $(GLINK2 function, MemberFunctionAttributes)$(OPT ) $(GLINK2 function, FunctionBody) ) $(DDOC_BLANKLINE ) $(P Shared static destructors are executed at program termination in the reverse order that $(GLINK SharedStaticConstructor)s were executed. ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 invariants, Class Invariants)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME Invariant): $(D invariant $(LPAREN) $(RPAREN )) $(GLINK2 statement, BlockStatement) $(D invariant) $(GLINK2 statement, BlockStatement) $(D invariant $(LPAREN)) $(GLINK2 expression, AssertArguments) $(D $(RPAREN ) ;) ) $(DDOC_BLANKLINE ) $(P Class $(I Invariant)s specify the relationships among the members of a class instance. Those relationships must hold for any interactions with the instance from its public interface. ) $(DDOC_BLANKLINE ) $(P The invariant is in the form of a $(D const) member function. The invariant is defined to $(I hold) if all the $(GLINK2 expression, AssertExpression)s within the invariant that are executed succeed. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD class) Date { $(D_KEYWORD this)($(D_KEYWORD int) d, $(D_KEYWORD int) h) { day = d; $(D_COMMENT // days are 1..31 ) hour = h; $(D_COMMENT // hours are 0..23 ) } $(D_KEYWORD invariant) { $(D_KEYWORD assert)(1 <= day && day <= 31); $(D_KEYWORD assert)(0 <= hour && hour < 24); } $(D_KEYWORD private): $(D_KEYWORD int) day; $(D_KEYWORD int) hour; } ) ) $(DDOC_BLANKLINE ) $(P Any class invariants for base classes are applied before the class invariant for the derived class.) $(DDOC_BLANKLINE ) $(P There may be multiple invariants in a class. They are applied in lexical order.) $(DDOC_BLANKLINE ) $(P Class $(I Invariant)s must hold at the exit of the class constructor (if any), and at the entry of the class destructor (if any).) $(DDOC_BLANKLINE ) $(P Class $(I Invariant)s must hold at the entry and exit of all public or exported non-static member functions. The order of application of invariants is:) $(OL $(LI preconditions) $(LI invariant) $(LI function body) $(LI invariant) $(LI postconditions) ) $(DDOC_BLANKLINE ) $(P If the invariant does not hold, then the program enters an invalid state.) $(DDOC_BLANKLINE ) $(IMPLEMENTATION_DEFINED $(OL $(LI Whether the class $(I Invariant) is executed at runtime or not. This is typically controlled with a compiler switch.) $(LI The behavior when the invariant does not hold is typically the same as for when $(GLINK2 expression, AssertExpression)s fail.) ) ) $(DDOC_BLANKLINE ) $(UNDEFINED_BEHAVIOR happens if the invariant does not hold and execution continues.) $(DDOC_BLANKLINE ) $(P Public or exported non-static member functions cannot be called from within an invariant.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) Foo { $(D_KEYWORD public) $(D_KEYWORD void) f() { } $(D_KEYWORD private) $(D_KEYWORD void) g() { } $(D_KEYWORD invariant) { f(); $(D_COMMENT // error, cannot call public member function from invariant ) g(); $(D_COMMENT // ok, g$(LPAREN)$(RPAREN ) is not public ) } } ) $(DDOC_BLANKLINE ) $(BEST_PRACTICE $(OL $(LI Do not indirectly call exported or public member functions within a class invariant, as this can result in infinite recursion.) $(LI Avoid reliance on side effects in the invariant. as the invariant may or may not be executed.) $(LI Avoid having mutable public fields of classes with invariants, as then the invariant cannot verify the public interface.) ) ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 auto, Scope Classes)

$(NOTE Scope classes have been $(DDSUBLINK deprecate, scope as a type constraint, deprecated). See also $(DDSUBLINK spec/attribute, scope-class-var, scope class instances).) $(DDOC_BLANKLINE ) $(P A scope class is a class with the $(D scope) attribute, as in:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD scope) $(D_KEYWORD class) Foo { ... } ) $(DDOC_BLANKLINE ) $(P The scope characteristic is inherited, so any classes derived from a scope class are also scope.) $(DDOC_BLANKLINE ) $(P A scope class reference can only appear as a function local variable. It must be declared as being $(D scope):) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD scope) $(D_KEYWORD class) Foo { ... } $(D_KEYWORD void) func() { Foo f; $(D_COMMENT // error, reference to scope class must be scope ) $(D_KEYWORD scope) Foo g = $(D_KEYWORD new) Foo(); $(D_COMMENT // correct )} ) $(DDOC_BLANKLINE ) $(P When a scope class reference goes out of scope, the destructor (if any) for it is automatically called. This holds true even if the scope was exited via a thrown exception.) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 abstract, Abstract Classes)

$(DDOC_BLANKLINE ) $(P An abstract member function must be overridden by a derived class. Only virtual member functions may be declared abstract; non-virtual member functions and free-standing functions cannot be declared abstract. ) $(DDOC_BLANKLINE ) $(P A class is abstract if any of its virtual member functions are declared abstract or if they are defined within an abstract attribute. Note that an abstract class may also contain non-virtual member functions. Abstract classes cannot be instantiated directly. They can only be instantiated as a base class of another, non-abstract, class. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_FAIL $(D_CODE $(D_KEYWORD class) C { $(D_KEYWORD abstract) $(D_KEYWORD void) f(); } $(D_KEYWORD auto) c = $(D_KEYWORD new) C; $(D_COMMENT // error, C is abstract ) $(D_KEYWORD class) D : C {} $(D_KEYWORD auto) d = $(D_KEYWORD new) D; $(D_COMMENT // error, D is abstract ) $(D_KEYWORD class) E : C { $(D_KEYWORD override) $(D_KEYWORD void) f() {} } $(D_KEYWORD auto) e = $(D_KEYWORD new) E; $(D_COMMENT // OK )) ) $(DDOC_BLANKLINE ) $(P Member functions declared as abstract can still have function bodies. This is so that even though they must be overridden, they can still provide $(SINGLEQUOTE base class functionality), e.g. through $(DDSUBLINK spec/expression, super, $(D super.foo())) in a derived class. Note that the class is still abstract and cannot be instantiated directly. ) $(DDOC_BLANKLINE ) $(P A class can be declared abstract: ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_FAIL $(D_CODE $(D_KEYWORD abstract) $(D_KEYWORD class) A { $(D_COMMENT // ... )} $(D_KEYWORD auto) a = $(D_KEYWORD new) A; $(D_COMMENT // error, A is abstract ) $(D_KEYWORD class) B : A {} $(D_KEYWORD auto) b = $(D_KEYWORD new) B; $(D_COMMENT // OK )) ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 final, Final Classes)

$(DDOC_BLANKLINE ) $(P Final classes cannot be subclassed:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD final) $(D_KEYWORD class) A { } $(D_KEYWORD class) B : A { } $(D_COMMENT // error, class A is final )) $(DDOC_BLANKLINE ) $(P Methods of a final class are always $(DDSUBLINK spec/function, final, final).) $(DDOC_BLANKLINE )

$(LNAME2 nested, Nested Classes)

$(DDOC_BLANKLINE ) $(P A $(I nested class) is a class that is declared inside the scope of a function or another class. A nested class has access to the variables and other symbols of the classes and functions it is nested inside:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) Outer { $(D_KEYWORD int) m; $(D_KEYWORD class) Inner { $(D_KEYWORD int) foo() { $(D_KEYWORD return) m; $(D_COMMENT // Ok to access member of Outer ) } } } ) $(D_CODE $(D_KEYWORD void) func() { $(D_KEYWORD int) m; $(D_KEYWORD class) Inner { $(D_KEYWORD int) foo() { $(D_KEYWORD return) m; $(D_COMMENT // Ok to access local variable m of func$(LPAREN)$(RPAREN ) ) } } } ) $(DDOC_BLANKLINE )

$(LNAME2 static-nested, Static Nested Classes)

$(DDOC_BLANKLINE ) $(P If a nested class has the $(D static) attribute, then it can not access variables of the enclosing scope that are local to the stack or need a this reference:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) Outer { $(D_KEYWORD int) m; $(D_KEYWORD static) $(D_KEYWORD int) n; $(D_KEYWORD static) $(D_KEYWORD class) Inner { $(D_KEYWORD int) foo() { $(D_KEYWORD return) m; $(D_COMMENT // Error, Inner is static and m needs a this ) $(D_KEYWORD return) n; $(D_COMMENT // Ok, n is static ) } } } ) $(D_CODE $(D_KEYWORD void) func() { $(D_KEYWORD int) m; $(D_KEYWORD static) $(D_KEYWORD int) n; $(D_KEYWORD static) $(D_KEYWORD class) Inner { $(D_KEYWORD int) foo() { $(D_KEYWORD return) m; $(D_COMMENT // Error, Inner is static and m is local to the stack ) $(D_KEYWORD return) n; $(D_COMMENT // Ok, n is static ) } } } ) $(DDOC_BLANKLINE )

$(LNAME2 nested-context, Context Pointer)

$(DDOC_BLANKLINE ) $(P Non-static nested classes work by containing an extra hidden member (called the context pointer) that is the frame pointer of the enclosing function if it is nested inside a function, or the $(D this) reference of the enclosing class's instance if it is nested inside a class.) $(DDOC_BLANKLINE ) $(P When a non-static nested class is instantiated, the context pointer is assigned before the class's constructor is called, therefore the constructor has full access to the enclosing variables. A non-static nested class can only be instantiated when the necessary context pointer information is available:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD class) Outer { $(D_KEYWORD class) Inner { } $(D_KEYWORD static) $(D_KEYWORD class) SInner { } } $(D_KEYWORD void) main() { Outer o = $(D_KEYWORD new) Outer; $(D_COMMENT // Ok ) $(D_COMMENT //Outer.Inner oi = new Outer.Inner; // Error, no 'this' for Outer ) Outer.SInner os = $(D_KEYWORD new) Outer.SInner; $(D_COMMENT // Ok )} ) ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD void) main() { $(D_KEYWORD class) Nested { } Nested n = $(D_KEYWORD new) Nested; $(D_COMMENT // Ok ) $(D_KEYWORD static) f() { $(D_COMMENT //Nested sn = new Nested; // Error, no 'this' for Nested ) } } ) ) $(DDOC_BLANKLINE )

$(LNAME2 nested-explicit, Explicit Instantiation)

$(DDOC_BLANKLINE ) $(P A this reference can be supplied to the creation of an inner class instance by prefixing it to the $(I NewExpression): ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD class) Outer { $(D_KEYWORD int) a; $(D_KEYWORD class) Inner { $(D_KEYWORD int) foo() { $(D_KEYWORD return) a; } } } $(D_KEYWORD void) main() { Outer o = $(D_KEYWORD new) Outer; o.a = 3; Outer.Inner oi = o.$(D_KEYWORD new) Inner; $(D_KEYWORD assert)(oi.foo() == 3); } ) ) $(DDOC_BLANKLINE ) $(P Here $(D o) supplies the this reference to the inner class instance of $(D Outer). ) $(DDOC_BLANKLINE )

$(LNAME2 outer-property, outer Property)

$(DDOC_BLANKLINE ) $(P For a nested class instance, the $(D .outer) property provides the $(D this) reference of the enclosing class's instance. If there is no accessible parent class instance, the property provides a $(D void*) to the enclosing function frame.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) Outer { $(D_KEYWORD class) Inner1 { Outer getOuter() { $(D_KEYWORD return) $(D_KEYWORD this).$(CODE_HIGHLIGHT outer); } } $(D_KEYWORD void) foo() { Inner1 i = $(D_KEYWORD new) Inner1; $(D_KEYWORD assert)(i.getOuter() $(D_KEYWORD is) $(D_KEYWORD this)); } } ) $(D_CODE $(D_KEYWORD class) Outer { $(D_KEYWORD void) bar() { $(D_COMMENT // x is referenced from nested scope, so ) $(D_COMMENT // bar makes a closure environment. ) $(D_KEYWORD int) x = 1; $(D_KEYWORD class) Inner2 { Outer getOuter() { x = 2; $(D_COMMENT // The Inner2 instance has access to the function frame ) $(D_COMMENT // of bar as a static frame pointer, but .outer returns ) $(D_COMMENT // the enclosing Outer class instance property. ) $(D_KEYWORD return) $(D_KEYWORD this).$(CODE_HIGHLIGHT outer); } } Inner2 i = $(D_KEYWORD new) Inner2; $(D_KEYWORD assert)(i.getOuter() $(D_KEYWORD is) $(D_KEYWORD this)); } } ) $(D_CODE $(D_KEYWORD class) Outer { $(D_COMMENT // baz cannot access an instance of Outer ) $(D_KEYWORD static) $(D_KEYWORD void) baz() { $(D_COMMENT // make a closure environment ) $(D_KEYWORD int) x = 1; $(D_KEYWORD class) Inner3 { $(D_KEYWORD void)* getOuter() { x = 2; $(D_COMMENT // There's no accessible enclosing class instance, so the ) $(D_COMMENT // .outer property returns the function frame of baz. ) $(D_KEYWORD return) $(D_KEYWORD this).$(CODE_HIGHLIGHT outer); } } Inner3 i = $(D_KEYWORD new) Inner3; $(D_KEYWORD assert)(i.getOuter() !$(D_KEYWORD is) $(D_KEYWORD null)); } } ) $(DDOC_BLANKLINE )

$(LNAME2 anonymous, Anonymous Nested Classes)

$(DDOC_BLANKLINE ) $(P An anonymous nested class is both defined and instantiated with a $(I NewAnonClassExpression): ) $(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME NewAnonClassExpression): $(D new) $(D class) $(GLINK ConstructorArgs)$(OPT ) $(GLINK AnonBaseClassList)$(OPT ) $(GLINK2 struct, AggregateBody) $(DDOC_BLANKLINE ) $(GNAME ConstructorArgs): $(D $(LPAREN)) $(GLINK2 expression, NamedArgumentList)$(OPT ) $(D $(RPAREN )) $(DDOC_BLANKLINE ) $(GNAME AnonBaseClassList): $(GLINK SuperClassOrInterface) $(GLINK SuperClassOrInterface) $(D ,) $(GLINK Interfaces) ) $(DDOC_BLANKLINE ) which is equivalent to: $(DDOC_BLANKLINE ) $(GRAMMAR_INFORMATIVE $(D class) $(GLINK_LEX Identifier) $(D :) $(I AnonBaseClassList) $(I AggregateBody) // ... $(D new) $(I Identifier) $(I ConstructorArgs) ) $(DDOC_BLANKLINE ) where $(I Identifier) is the name generated for the anonymous nested class. $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD interface) I { $(D_KEYWORD void) foo(); } $(D_KEYWORD auto) obj = $(D_KEYWORD new) $(D_KEYWORD class) I { $(D_KEYWORD void) foo() { writeln($(D_STRING "foo")); } }; obj.foo(); ) ) $(DDOC_BLANKLINE ) $(SECTION2 $(LEGACY_LNAME2 ConstClass, const-class, $(ARGS Const, Immutable and Shared Classes)), $(DDOC_BLANKLINE ) $(P If a $(I ClassDeclaration) has a $(D const), $(D immutable) or $(D shared) storage class, then it is as if each member of the class was declared with that storage class. If a base class is const, immutable or shared, then all classes derived from it are also const, immutable or shared. ) ) $(SPEC_SUBNAV_PREV_NEXT struct, Structs and Unions, interface, Interfaces) ) )