Adding additional modules (files) to your program
As your program grows, you'll want to break it up across multiple files. D offers a way to do this that is similar, but not identical to other popular programming languages. D source files are also called D modules.
How to do it…
Let's add modules to your program by executing the following steps:
Create an additional file.
Put the
module
declaration in the other file with a package and module name. These names should be meaningful for your project and this specific file, respectively, as shown:module yourpackage.yourmodulename;;;
Import it in the existing file to use it. Import works in different ways—it does not have to be at the top of the file and may appear more than once in the file. The
import
statement should always match the full name given in themodule
statement in the file being imported, as shown in the following code:import yourpackage.yourmodulename;
Use the functions, disambiguating with the full module name if required.
Compile with all files listed on the command line using the following syntax:
dmd file1.d file2.d
This will produce a single executable file out of the passed files. The name of the executable is, by default, the same as the first file passed. So here, the executable file will be named
file1
.
How it works…
In D, code is organized into modules. There is a one-to-one correspondence between files and modules—every D source file is a module, and every D module is a file. Using a module involves importing it into the current scope, accessing its members in code, and adding it to the build command when compiling.
Tip
If you forget to add a module to the build command, you'll see an error such as cannot find module of name NAME
or undefined symbol _D6module
.
Modules are conceptually similar to static classes with a single instance; they can have constructors, destructors, fields, and so on. Each declaration inside a module may have attributes and protection qualifiers. In D, unlike C++, modules (not classes) are the unit of encapsulation. Therefore, any code can access any entity within the same module (regardless of the entity's protection qualifier).
Modules have logical names that do not need to match the filename. This is set with the module
statement, which must appear at the top of the file. The module
statement is not strictly required. If you leave it off, it will default to the filename. However, it is strongly recommended that you write it, including a package name, (the first part of the dot-separated full name) in every module that may ever be imported, because relying on the default module name will cause trouble if you organize your code into directories. The common error module foo.bar
must be imported as the foo
module is caused by a missing module
statement in the imported module. The typical organization of modules into packages mirrors the source files' directory structures. You are to match package and module names with directory and filenames, but doing so will help other users and build tools understand your project layout.
The import
statement may appear at any point. In module scope, it may appear anywhere and any number of times without changing anything. It can also be used in local scopes, where it must appear before the member is used and visibility is limited to that scope.
Names of members in a module are not required to be unique among all the modules that make up a program. Instead, when necessary, they are disambiguated at the usage point or at the import
statement by the module identifier, as shown in the following code:
import project.foo;; // disambiguate with project.foo import bar; // you can disambiguate calls with the name bar project.foo.func(); // call project.foo.func bar.func(); // call bar.func
The compiler will always issue an error if a reference is ambiguous so that you can specify your intent.
Tip
You can also rename modules when you import them. The statement, import foo = project.foo;
will then allow you to use foo
to disambiguate a name instead of having to write out the full project.foo
name every time.
There's more…
The dmd
distribution also includes a program called rdmd
, which can recursively find dependent modules and compile them all automatically. With rdmd
, you only have to pass the module that contains main
.
See also
The module documentation at http://dlang.org/module.html details how D's module system works, including a list of all the forms of the
import
statement and information about symbol protection