$(DDOC $(DDOC_BLANKLINE )
$(DDOC_BLANKLINE )
$(SPEC_S Modules,
$(DDOC_BLANKLINE )
$(HEADERNAV_TOC $(HEADERNAV_SUBITEMS module_declaration, Module Declaration,
$(HEADERNAV_ITEM deprecated_modules, Deprecated modules)
)
$(HEADERNAV_SUBITEMS import-declaration, Import Declaration,
$(HEADERNAV_ITEM name_lookup, Symbol Name Lookup)
$(HEADERNAV_ITEM public_imports, Public Imports)
$(HEADERNAV_ITEM static_imports, Static Imports)
$(HEADERNAV_ITEM renamed_imports, Renamed Imports)
$(HEADERNAV_ITEM selective_imports, Selective Imports)
$(HEADERNAV_ITEM renamed_selective_imports, Renamed and Selective Imports)
$(HEADERNAV_ITEM scoped_imports, Scoped Imports)
)
$(HEADERNAV_ITEM module_scope_operators, Module Scope Operator)
$(HEADERNAV_SUBITEMS staticorder, Static Construction and Destruction,
$(HEADERNAV_ITEM order_of_static_ctor, Order of Static Construction)
$(HEADERNAV_ITEM order_of_static_ctors, Order of Static Construction within a Module)
$(HEADERNAV_ITEM order_static_dtor, Order of Static Destruction)
)
$(HEADERNAV_ITEM order_of_unittests, Order of Unit tests)
$(HEADERNAV_ITEM mixin-declaration, Mixin Declaration)
$(HEADERNAV_ITEM package-module, Package Module)
)
$(DDOC_BLANKLINE )
$(GRAMMAR $(GNAME Module):
$(GLINK ModuleDeclaration)
$(GLINK ModuleDeclaration) $(GLINK DeclDefs)
$(GLINK DeclDefs)
$(DDOC_BLANKLINE )
$(GNAME DeclDefs):
$(GLINK DeclDef)
$(GLINK DeclDef) $(GSELF DeclDefs)
$(DDOC_BLANKLINE )
$(GNAME DeclDef):
$(GLINK2 attribute, AttributeSpecifier)
$(GLINK2 declaration, Declaration)
$(GLINK2 class, Constructor)
$(GLINK2 class, Destructor)
$(GLINK2 struct, Postblit)
$(GLINK2 class, Invariant)
$(GLINK2 unittest, UnitTest)
$(GLINK2 class, AliasThis)
$(GLINK2 class, StaticConstructor)
$(GLINK2 class, StaticDestructor)
$(GLINK2 class, SharedStaticConstructor)
$(GLINK2 class, SharedStaticDestructor)
$(GLINK2 version, ConditionalDeclaration)
$(GLINK2 version, DebugSpecification)
$(GLINK2 version, VersionSpecification)
$(GLINK MixinDeclaration)
$(GLINK EmptyDeclaration)
$(DDOC_BLANKLINE )
$(GNAME EmptyDeclaration):
$(D ;)
)
$(DDOC_BLANKLINE )
$(P Modules have a one-to-one correspondence with source files. When not
explicitly set via a $(GLINK ModuleDeclaration), a module's name defaults
to the name of the file stripped of its path and extension.)
$(DDOC_BLANKLINE )
$(P A module's name automatically acts as a namespace scope for its contents. Modules
superficially resemble classes, but differ in that:)
$(DDOC_BLANKLINE )
$(UL $(LI Only one instance of a module exists, and it is
statically allocated.)
$(DDOC_BLANKLINE )
$(LI Modules do not have virtual tables.)
$(DDOC_BLANKLINE )
$(LI Modules do not inherit, do not have super modules, etc.)
$(DDOC_BLANKLINE )
$(LI A source file may contain only one module.)
$(DDOC_BLANKLINE )
$(LI Symbols in a module can be imported.)
$(DDOC_BLANKLINE )
$(LI Modules are always compiled at global scope and are unaffected
by surrounding attributes or other modifiers.)
)
$(DDOC_BLANKLINE )
$(P Modules can be grouped into hierarchies called $(I packages).)
$(DDOC_BLANKLINE )
$(P Modules offer several guarantees:)
$(DDOC_BLANKLINE )
$(UL $(DDOC_BLANKLINE )
$(LI The order in which modules are imported does not affect their
semantics.)
$(DDOC_BLANKLINE )
$(LI The semantics of a module are not affected by the scope in which
it is imported.)
$(DDOC_BLANKLINE )
$(LI If a module $(D C) imports modules $(D A) and $(D B), any modifications
to $(D B) will not silently change code in $(D C) that is dependent on $(D A).)
)
$(DDOC_BLANKLINE )
$(LNAME2 module_declaration, Module Declaration)
$(DDOC_BLANKLINE )
$(P The $(I ModuleDeclaration) sets the name of the module and what package it
belongs to. If absent, the module name is taken to be the same name (stripped of
path and extension) of the source file name.)
$(DDOC_BLANKLINE )
$(GRAMMAR $(GNAME ModuleDeclaration):
$(GLINK ModuleAttributes)$(OPT ) $(D module) $(GLINK ModuleFullyQualifiedName) $(D ;)
$(DDOC_BLANKLINE )
$(GNAME ModuleAttributes):
$(GLINK ModuleAttribute)
$(GLINK ModuleAttribute) $(GSELF ModuleAttributes)
$(DDOC_BLANKLINE )
$(GNAME ModuleAttribute):
$(GLINK2 attribute, DeprecatedAttribute)
$(GLINK2 attribute, UserDefinedAttribute)
$(DDOC_BLANKLINE )
$(GNAME ModuleFullyQualifiedName):
$(GLINK ModuleName)
$(GLINK Packages) $(D .) $(GLINK ModuleName)
$(DDOC_BLANKLINE )
$(GNAME ModuleName):
$(GLINK_LEX Identifier)
)
$(GRAMMAR $(GNAME Packages):
$(GLINK PackageName)
$(GSELF Packages) $(D .) $(GLINK PackageName)
$(DDOC_BLANKLINE )
$(GNAME PackageName):
$(GLINK_LEX Identifier)
)
$(DDOC_BLANKLINE )
$(P The $(I Identifier)s preceding the rightmost $(I Identifier) are the $(I Packages) that the
module is in. The packages correspond to directory names in the source file
path. Package and module names cannot be $(GLINK_LEX Keyword)s.)
$(DDOC_BLANKLINE )
$(P If present, the $(I ModuleDeclaration) must be the first and only such declaration
in the source file, and may be preceded only by comments and $(D #line) directives.)
$(DDOC_BLANKLINE )
$(P Example:)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD module) c.stdio; $(D_COMMENT // module stdio in the c package
))
$(DDOC_BLANKLINE )
$(P By convention, package and module names are all lower case. This is because
these names have a one-to-one correspondence with the operating system's
directory and file names, and many file systems are not case sensitive. Using all
lower case package and module names will avoid or minimize problems when moving projects
between dissimilar file systems.)
$(DDOC_BLANKLINE )
$(P If the file name of a module is an invalid module name (e.g.
foo-bar.d
), use a module declaration to set a valid module name:)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD module) foo_bar;
)
$(DDOC_BLANKLINE )
$(IMPLEMENTATION_DEFINED $(OL $(LI The mapping of package and module identifiers to directory and file names.)
))
$(DDOC_BLANKLINE )
$(BEST_PRACTICE $(OL $(LI $(GLINK PackageName)s and $(GLINK ModuleName)s should be composed of the ASCII
characters lower case letters, digits or _
to ensure maximum portability and compatibility with
various file systems.)
$(LI The file names for packages and modules should be composed only of
the ASCII lower case letters, digits, and _
s, and should not be a $(GLINK_LEX Keyword).)
))
$(DDOC_BLANKLINE )
$(LNAME2 deprecated_modules, Deprecated modules)
$(DDOC_BLANKLINE )
$(P A $(I ModuleDeclaration) can have an optional $(GLINK2 attribute,
DeprecatedAttribute). The compiler will produce a message when the deprecated
module is imported.)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD deprecated) $(D_KEYWORD module) foo;
)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD module) bar;
$(D_KEYWORD import) foo; $(D_COMMENT // Deprecated: module foo is deprecated
))
$(DDOC_BLANKLINE )
$(P A $(I DeprecatedAttribute) can have an optional $(ASSIGNEXPRESSION ) argument to provide a
more informative message. The $(I AssignExpression) must evaluate to a string at compile time.
)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD deprecated)($(D_STRING "Please use foo2 instead."))
$(D_KEYWORD module) foo;
)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD module) bar;
$(D_KEYWORD import) foo; $(D_COMMENT // Deprecated: module foo is deprecated - Please use foo2 instead.
))
$(DDOC_BLANKLINE )
$(IMPLEMENTATION_DEFINED $(OL $(LI How the deprecation messages are presented to the user.)
))
$(DDOC_BLANKLINE )
$(DDOC_BLANKLINE )
$(LEGACY_LNAME2 ImportDeclaration, import-declaration, Import Declaration)
$(DDOC_BLANKLINE )
$(P Symbols from one module are made available in another module by using the
$(I ImportDeclaration):)
$(DDOC_BLANKLINE )
$(GRAMMAR $(GNAME ImportDeclaration):
$(D import) $(GLINK ImportList) $(D ;)
$(D static import) $(GLINK ImportList) $(D ;)
$(DDOC_BLANKLINE )
$(GNAME ImportList):
$(GLINK Import)
$(GLINK ImportBindings)
$(GLINK Import) $(D ,) $(GSELF ImportList)
$(DDOC_BLANKLINE )
$(GNAME Import):
$(GLINK ModuleFullyQualifiedName)
$(GLINK ModuleAliasIdentifier) $(D =) $(GLINK ModuleFullyQualifiedName)
$(DDOC_BLANKLINE )
$(GNAME ImportBindings):
$(GLINK Import) $(D :) $(GLINK ImportBindList)
$(DDOC_BLANKLINE )
$(GNAME ImportBindList):
$(GLINK ImportBind)
$(GLINK ImportBind) $(D ,) $(GSELF ImportBindList)
$(DDOC_BLANKLINE )
$(GNAME ImportBind):
$(GLINK_LEX Identifier)
$(GLINK_LEX Identifier) $(D =) $(GLINK_LEX Identifier)
$(DDOC_BLANKLINE )
$(GNAME ModuleAliasIdentifier):
$(GLINK_LEX Identifier)
)
$(DDOC_BLANKLINE )
$(P There are several forms of the $(I ImportDeclaration), from generalized to
fine-grained importing.)
$(DDOC_BLANKLINE )
$(P The order in which $(I ImportDeclaration)s occur has no significance.)
$(DDOC_BLANKLINE )
$(P $(I ModuleFullyQualifiedName)s in the $(I ImportDeclaration) must be fully
qualified with whatever packages they are in. They are not considered to be
relative to the module that imports them.)
$(DDOC_BLANKLINE )
$(LNAME2 name_lookup, Symbol Name Lookup)
$(DDOC_BLANKLINE )
$(P The simplest form of importing is to just list the modules being imported:)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD module) myapp.main;
$(D_KEYWORD import) std.stdio; $(D_COMMENT // import module stdio from package std
)
$(D_KEYWORD class) Foo : BaseClass
{
$(D_KEYWORD import) myapp.foo; $(D_COMMENT // import module myapp.foo in this class' scope
) $(D_KEYWORD void) bar ()
{
$(D_KEYWORD import) myapp.bar; $(D_COMMENT // import module myapp.bar in this function' scope
) writeln($(D_STRING "hello!")); $(D_COMMENT // calls std.stdio.writeln
) }
}
)
$(DDOC_BLANKLINE )
$(P When a symbol name is used unqualified, a two-phase lookup is used.
First, the module scope is searched, starting from the innermost scope.
For example, in the previous example, while looking for writeln
,
the order will be:)
$(DDOC_BLANKLINE )
$(UL $(LI Declarations inside bar
.)
$(LI Declarations inside Foo
.)
$(LI Declarations inside BaseClass
.)
$(LI Declarations at module scope.)
)
$(DDOC_BLANKLINE )
$(P If the first lookup isn't successful, a second one is performed on imports.
In the second lookup phase inherited scopes are ignored. This includes the scope of
base classes and interfaces (in this example, BaseClass
's imports
would be ignored), as well as imports in mixed-in $(D template).)
$(DDOC_BLANKLINE )
$(P Symbol lookup stops as soon as a matching symbol is found. If two symbols with the
same name are found at the same lookup phase, this ambiguity will result in a
compilation error.)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD module) A;
$(D_KEYWORD void) foo();
$(D_KEYWORD void) bar();
)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD module) B;
$(D_KEYWORD void) foo();
$(D_KEYWORD void) bar();
)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD module) C;
$(D_KEYWORD import) A;
$(D_KEYWORD void) foo();
$(D_KEYWORD void) test()
{
foo(); $(D_COMMENT // C.foo$(LPAREN)$(RPAREN ) is called, it is found before imports are searched
) bar(); $(D_COMMENT // A.bar$(LPAREN)$(RPAREN ) is called, since imports are searched
)}
)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD module) D;
$(D_KEYWORD import) A;
$(D_KEYWORD import) B;
$(D_KEYWORD void) test()
{
foo(); $(D_COMMENT // error, A.foo$(LPAREN)$(RPAREN ) or B.foo$(LPAREN)$(RPAREN ) ?
) A.foo(); $(D_COMMENT // ok, call A.foo$(LPAREN)$(RPAREN )
) B.foo(); $(D_COMMENT // ok, call B.foo$(LPAREN)$(RPAREN )
)}
)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD module) E;
$(D_KEYWORD import) A;
$(D_KEYWORD import) B;
$(D_KEYWORD alias) foo = B.foo;
$(D_KEYWORD void) test()
{
foo(); $(D_COMMENT // call B.foo$(LPAREN)$(RPAREN )
) A.foo(); $(D_COMMENT // call A.foo$(LPAREN)$(RPAREN )
) B.foo(); $(D_COMMENT // call B.foo$(LPAREN)$(RPAREN )
)}
)
$(DDOC_BLANKLINE )
$(LNAME2 public_imports, Public Imports)
$(DDOC_BLANKLINE )
$(P By default, imports are $(I private). This means that if module A imports
module B, and module B imports module C, then names inside C are visible only inside
B and not inside A.)
$(DDOC_BLANKLINE )
$(P An import can be explicitly declared $(I public), which will cause
names from the imported module to be visible to further imports. So in the above
example where module A imports module B, if module B $(I publicly) imports
module C, names from C will be visible in A as well.)
$(DDOC_BLANKLINE )
$(P All symbols from a publicly imported module are also aliased in the
importing module. Thus in the above example if C contains the name foo, it will
be accessible in A as $(D foo), $(D B.foo) and $(D C.foo).)
$(DDOC_BLANKLINE )
$(P For another example:)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD module) W;
$(D_KEYWORD void) foo() { }
)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD module) X;
$(D_KEYWORD void) bar() { }
)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD module) Y;
$(D_KEYWORD import) W;
$(D_KEYWORD public) $(D_KEYWORD import) X;
...
foo(); $(D_COMMENT // calls W.foo$(LPAREN)$(RPAREN )
)bar(); $(D_COMMENT // calls X.bar$(LPAREN)$(RPAREN )
))
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD module) Z;
$(D_KEYWORD import) Y;
...
foo(); $(D_COMMENT // error, foo$(LPAREN)$(RPAREN ) is undefined
)bar(); $(D_COMMENT // ok, calls X.bar$(LPAREN)$(RPAREN )
)X.bar(); $(D_COMMENT // ditto
)Y.bar(); $(D_COMMENT // ok, Y.bar$(LPAREN)$(RPAREN ) is an alias to X.bar$(LPAREN)$(RPAREN )
))
$(DDOC_BLANKLINE )
$(LNAME2 static_imports, Static Imports)
$(DDOC_BLANKLINE )
$(P A static import requires the use of a fully qualified name
to reference the module's names:)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD static) $(D_KEYWORD import) std.stdio;
$(D_KEYWORD void) main()
{
writeln($(D_STRING "hello!")); $(D_COMMENT // error, writeln is undefined
) std.stdio.writeln($(D_STRING "hello!")); $(D_COMMENT // ok, writeln is fully qualified
)}
)
$(DDOC_BLANKLINE )
$(LNAME2 renamed_imports, Renamed Imports)
$(DDOC_BLANKLINE )
$(P A local name for an import can be given, through which all references to the
module's symbols must be qualified with:)
$(DDOC_BLANKLINE )
$(RUNNABLE_EXAMPLE $(D_CODE $(D_KEYWORD import) io = std.stdio;
$(D_KEYWORD void) main()
{
io.writeln($(D_STRING "hello!")); $(D_COMMENT // ok, calls std.stdio.writeln
) std.stdio.writeln($(D_STRING "hello!")); $(D_COMMENT // error, std is undefined
) writeln($(D_STRING "hello!")); $(D_COMMENT // error, writeln is undefined
)}
)
)
$(DDOC_BLANKLINE )
$(BEST_PRACTICE Renamed imports are handy when dealing with very long import names.)
$(DDOC_BLANKLINE )
$(LNAME2 selective_imports, Selective Imports)
$(DDOC_BLANKLINE )
$(P Specific symbols can be exclusively imported from a module and bound into
the current namespace:)
$(DDOC_BLANKLINE )
$(SPEC_RUNNABLE_EXAMPLE_FAIL $(D_CODE $(D_KEYWORD import) std.stdio : writeln, foo = write;
$(D_KEYWORD void) main()
{
std.stdio.writeln($(D_STRING "hello!")); $(D_COMMENT // error, std is undefined
) writeln($(D_STRING "hello!")); $(D_COMMENT // ok, writeln bound into current namespace
) write($(D_STRING "world")); $(D_COMMENT // error, write is undefined
) foo($(D_STRING "world")); $(D_COMMENT // ok, calls std.stdio.write$(LPAREN)$(RPAREN )
) fwritefln(stdout, $(D_STRING "abc")); $(D_COMMENT // error, fwritefln undefined
)}
)
)
$(DDOC_BLANKLINE )
$(P $(D static) cannot be used with selective imports.)
$(DDOC_BLANKLINE )
$(LNAME2 renamed_selective_imports, Renamed and Selective Imports)
$(DDOC_BLANKLINE )
$(P When renaming and selective importing are combined:)
$(DDOC_BLANKLINE )
$(SPEC_RUNNABLE_EXAMPLE_FAIL $(D_CODE $(D_KEYWORD import) io = std.stdio : foo = writeln;
$(D_KEYWORD void) main()
{
writeln($(D_STRING "bar")); $(D_COMMENT // error, writeln is undefined
) std.stdio.foo($(D_STRING "bar")); $(D_COMMENT // error, foo is bound into current namespace
) std.stdio.writeln($(D_STRING "bar")); $(D_COMMENT // error, std is undefined
) foo($(D_STRING "bar")); $(D_COMMENT // ok, foo is bound into current namespace,
) $(D_COMMENT // FQN not required
) io.writeln($(D_STRING "bar")); $(D_COMMENT // ok, io=std.stdio bound the name io in
) $(D_COMMENT // the current namespace to refer to the entire
) $(D_COMMENT // module
) io.foo($(D_STRING "bar")); $(D_COMMENT // error, foo is bound into current namespace,
) $(D_COMMENT // foo is not a member of io
)}
)
)
$(DDOC_BLANKLINE )
$(LNAME2 scoped_imports, Scoped Imports)
$(DDOC_BLANKLINE )
$(P Import declarations may be used at any scope. For example:)
$(DDOC_BLANKLINE )
$(RUNNABLE_EXAMPLE $(D_CODE $(D_KEYWORD void) main()
{
$(D_KEYWORD import) std.stdio;
writeln($(D_STRING "bar"));
}
)
)
$(DDOC_BLANKLINE )
$(P The imports are looked up to satisfy any unresolved symbols at that scope.
Imported symbols may hide symbols from outer scopes.)
$(DDOC_BLANKLINE )
$(P In function scopes, imported symbols only become visible after the import
declaration lexically appears in the function body. In other words, imported
symbols at function scope cannot be forward referenced.)
$(DDOC_BLANKLINE )
$(RUNNABLE_EXAMPLE $(D_CODE $(D_KEYWORD void) main()
{
$(D_KEYWORD void) writeln(string) {}
$(D_KEYWORD void) foo()
{
writeln($(D_STRING "bar")); $(D_COMMENT // calls main.writeln
) $(D_KEYWORD import) std.stdio;
writeln($(D_STRING "bar")); $(D_COMMENT // calls std.stdio.writeln
) $(D_KEYWORD void) writeln(string) {}
writeln($(D_STRING "bar")); $(D_COMMENT // calls main.foo.writeln
) }
writeln($(D_STRING "bar")); $(D_COMMENT // calls main.writeln
) std.stdio.writeln($(D_STRING "bar")); $(D_COMMENT // error, std is undefined
)}
)
)
$(DDOC_BLANKLINE )
$(LNAME2 module_scope_operators, Module Scope Operator)
$(DDOC_BLANKLINE )
$(P A leading dot (.
) causes the
identifier to be looked up in the module scope.)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD int) x;
$(D_KEYWORD int) foo($(D_KEYWORD int) x)
{
$(D_KEYWORD if) (y)
$(D_KEYWORD return) x; $(D_COMMENT // returns foo.x, not global x
) $(D_KEYWORD else)
$(D_KEYWORD return) .x; $(D_COMMENT // returns global x
)}
)
$(DDOC_BLANKLINE )
$(DDOC_BLANKLINE )
$(LNAME2 staticorder, Static Construction and Destruction)
$(DDOC_BLANKLINE )
$(P Static constructors are executed to initialize a module's state.
Static destructors terminate a module's state.
)
$(DDOC_BLANKLINE )
$(P A module may have multiple static constructors and static destructors.
The static constructors are run in lexical order, the static destructors
are run in reverse lexical order.)
$(DDOC_BLANKLINE )
$(P Non-shared static constructors and destructors are
run whenever threads are created or destroyed, including the main thread.)
$(DDOC_BLANKLINE )
$(P Shared static constructors are run once before main()
is called.
Shared static destructors are run after the main()
function returns.
)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD import) resource;
Resource x;
$(D_KEYWORD shared) Resource y;
$(D_KEYWORD __gshared) Resource z;
$(D_KEYWORD static) $(D_KEYWORD this)() $(D_COMMENT // non-shared static constructor
){
x = acquireResource();
}
$(D_KEYWORD shared) $(D_KEYWORD static) $(D_KEYWORD this)() $(D_COMMENT // shared static constructor
){
y = acquireSharedResource();
z = acquireSharedResource();
}
$(D_KEYWORD static) ~$(D_KEYWORD this)() $(D_COMMENT // non-shared static destructor
){
releaseResource(x);
}
$(D_KEYWORD shared) $(D_KEYWORD static) ~$(D_KEYWORD this)() $(D_COMMENT // shared static destructor
){
releaseSharedResource(y);
releaseSharedResource(z);
}
)
$(DDOC_BLANKLINE )
$(BEST_PRACTICE $(OL $(LI Shared static constructors and destructors are used to initialize and terminate
shared global data.)
$(LI Non-shared static constructors and destructors are used to initialize and terminate
thread local data.)
))
$(DDOC_BLANKLINE )
$(LNAME2 order_of_static_ctor, Order of Static Construction)
$(DDOC_BLANKLINE )
$(P Shared static constructors on all modules are run before any non-shared static
constructors.)
$(DDOC_BLANKLINE )
$(P The order of static initialization is implicitly determined by the $(I import) declarations in each module. Each module is assumed to depend on any
imported modules being statically constructed first.
There is no other order imposed on the execution of module static constructors.)
$(DDOC_BLANKLINE )
$(P Cycles (circular dependencies) in the import declarations are allowed so
long as neither, or one, but not both, of the modules, contains static constructors or static
destructors. Violation of this rule will result in a runtime exception.)
$(DDOC_BLANKLINE )
$(IMPLEMENTATION_DEFINED $(OL $(LI An implementation may provide a means of overriding the cycle detection abort.
A typical method uses the D Runtime switch
--DRT-oncycle=...
where the following behaviors are supported:
$(OL $(LI abort
The default behavior. The normal behavior as described
in the previous section.)
$(LI print
Print all cycles detected, but do not abort execution.
When cycles are present, the order of static construction is
implementation defined, and not guaranteed to be valid.)
$(LI ignore
Do not abort execution or print any cycles. When
cycles are present, the order of static construction is implementation
defined, and not guaranteed to be valid.)
)
))
)
$(DDOC_BLANKLINE )
$(BEST_PRACTICE $(OL $(LI Avoid cyclical imports where practical. They can be an indication of poor
decomposition of a program's structure into independent modules. Two modules
that import each other can often be reorganized into three modules without
cycles, where the third contains the declarations needed by the other two.)
)
)
$(DDOC_BLANKLINE )
$(LNAME2 order_of_static_ctors, Order of Static Construction within a Module)
$(DDOC_BLANKLINE )
$(P Within a module, static construction occurs in the lexical order in
which they appear.)
$(DDOC_BLANKLINE )
$(LNAME2 order_static_dtor, Order of Static Destruction)
$(DDOC_BLANKLINE )
$(P This is defined to be in exactly the reverse order of static construction.
Static destructors for individual modules will only be run if the
corresponding static constructor successfully completed.)
$(DDOC_BLANKLINE )
$(P Shared static destructors are executed after static destructors.)
$(DDOC_BLANKLINE )
$(LNAME2 order_of_unittests, Order of Unit tests)
$(DDOC_BLANKLINE )
$(P Unit tests are run in the lexical order in which they appear within a
module.)
$(DDOC_BLANKLINE )
$(LEGACY_LNAME2 MixinDeclaration, mixin-declaration, Mixin Declaration)
$(DDOC_BLANKLINE )
$(GRAMMAR $(GNAME MixinDeclaration):
$(D mixin) $(D $(LPAREN)) $(GLINK2 expression, ArgumentList) $(D $(RPAREN )) $(D ;)
)
$(DDOC_BLANKLINE )
$(P Each $(GLINK2 expression, AssignExpression) in the $(I ArgumentList) is
evaluated at compile time, and the result must be representable
as a string.
The resulting strings are concatenated to form a string.
The text contents of the string must be compilable as valid
$(GLINK DeclDefs), and is compiled as such.)
$(DDOC_BLANKLINE )
$(P The content of a mixin cannot be forward referenced by other DeclDefs of
the same scope because it is not yet pulled into the AST.)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD class) B : A {} $(D_COMMENT // Error: undefined identifier `A`
)$(D_KEYWORD mixin) ($(D_STRING "class A {}"));
)
$(DDOC_BLANKLINE )
$(P Forward references may only work in function bodies because they
are processed after the declarations:)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD void) v()
{
$(D_KEYWORD class) B : A {}
}
$(D_KEYWORD mixin) ($(D_STRING "class A {}"));
)
$(DDOC_BLANKLINE )
$(LEGACY_LNAME2 PackageModule, package-module, Package Module)
$(DDOC_BLANKLINE )
$(P A package module can be used to publicly import other modules, while
providing a simpler import syntax. This enables the conversion of a module into a package
of modules, without breaking existing code which uses that module. Example of a
set of library modules:)
$(DDOC_BLANKLINE )
$(B libweb/client.d:)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD module) libweb.client;
$(D_KEYWORD void) runClient() { }
)
$(DDOC_BLANKLINE )
$(B libweb/server.d:)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD module) libweb.server;
$(D_KEYWORD void) runServer() { }
)
$(DDOC_BLANKLINE )
$(B libweb/package.d:)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD module) libweb;
$(D_KEYWORD public) $(D_KEYWORD import) libweb.client;
$(D_KEYWORD public) $(D_KEYWORD import) libweb.server;
)
$(DDOC_BLANKLINE )
$(P The package module's file name must be $(D package.d). The module name
is declared to be the fully qualified name of the package. Package modules can
be imported just like any other modules:)
$(DDOC_BLANKLINE )
$(B test.d:)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD module) test;
$(D_COMMENT // import the package module
)$(D_KEYWORD import) libweb;
$(D_KEYWORD void) main()
{
runClient();
runServer();
}
)
$(DDOC_BLANKLINE )
$(P A package module can be nested inside of a sub-package:)
$(DDOC_BLANKLINE )
$(B libweb/utils/package.d:)
$(DDOC_BLANKLINE )
$(D_CODE $(D_COMMENT // must be declared as the fully qualified name of the package, not just 'utils'
)$(D_KEYWORD module) libweb.utils;
$(D_COMMENT // publicly import modules from within the 'libweb.utils' package.
)$(D_KEYWORD public) $(D_KEYWORD import) libweb.utils.conv;
$(D_KEYWORD public) $(D_KEYWORD import) libweb.utils.text;
)
$(DDOC_BLANKLINE )
$(P The package module can then be imported with the standard module import
declaration:)
$(DDOC_BLANKLINE )
$(B test.d:)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD module) test;
$(D_COMMENT // import the package module
)$(D_KEYWORD import) libweb.utils;
$(D_KEYWORD void) main() { }
)
$(DDOC_BLANKLINE )
$(SPEC_SUBNAV_PREV_NEXT grammar, Grammar, declaration, Declarations)
)
)