$(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)
)
)