[Home]
[Search]
[D]
Last update Jan 14, 2002
Modules
Modules have a one-to-one correspondence with source files.
The module name is the file name with the path and extension
stripped off.
Modules automatically provide a namespace scope for their contents.
Modules superficially resemble classes, but differ in that:
- There's only one instance of each module, and it is
statically allocated.
- There is no virtual table.
- Modules do not inherit, they have no super modules, etc.
- Only one module per file.
- Module symbols can be imported.
- Modules are always compiled at global scope, and are unaffected
by surrounding attributes or other modifiers.
Module Declaration
The 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.
ModuleDeclaration:
module ModuleName ;
ModuleName:
Identifier
ModuleName . Identifier
The Identifier preceding the rightmost are the packages
that the module is in. The packages correspond to directory names in
the source file path.
If present, the ModuleDeclaration appears syntactically first
in the source file, and there can be only one per source file.
Example:
module c.stdio; // this is module stdio in the c package
By convention, package and module names are all lower case. This is
because those names have a one-to-one correspondence with the operating
system's directory and file names, and many file systems
are not case sensitive. All lower case package and module names will
minimize problems moving projects between dissimilar file systems.
Import Declaration
Rather than text include files, D imports symbols symbolically with the
import declaration:
ImportDeclaration:
import ModuleNameList ;
ModuleNameList:
ModuleName
ModuleName , ModuleNameList
The rightmost Identifier becomes the module name.
The top level scope in the module is merged with the current scope.
Example:
import c.stdio; // import module stdio from the c package
import foo, bar; // import modules foo and bar
Scope and Modules
Each module forms its own namespace. When a module is imported
into another module, all its top level declarations are
available without qualification. Ambiguities are illegal, and
can be resolved by explicitly qualifying the symbol with the
module name.
For example, assume the following modules:
Module foo
int x = 1;
int y = 2;
Module bar
int y = 3;
int z = 4;
then:
import foo;
...
q = y; // sets q to foo.y
and:
import foo;
int y = 5;
q = y; // local y overrides foo.y
and:
import foo;
import bar;
q = y; // error: foo.y or bar.y?
and:
import foo;
import bar;
q = bar.y; // q set to 3
Static Construction and Destruction
Static constructors are code that gets executed to initialize
a module or a class before the main() function gets called.
Static destructors are code that gets executed after the main()
function returns, and are normally used for releasing
system resources.
Order of Static Construction
The order of static initialization is implicitly determined by
the import declarations in each module. Each module is
assumed to depend on any imported modules being statically
constructed first.
Other than following that rule, there is no imposed order
on executing the module static constructors.
Cycles (circular dependencies) in the import declarations are
allowed as long as not both of the modules contain static constructors
or static destructors. Violation of this rule will result
in a runtime exception.
Order of Static Construction within a Module
Within a module, the static construction occurs in the lexical
order in which they appear.
Order of Static Destruction
It is defined to be exactly the reverse order that static
construction was performed in. Static destructors for individual
modules will only be run if the corresponding static constructor
successfully completed.
Copyright (c) 1999-2001 by Digital Mars, All Rights Reserved