Book Image

D Cookbook

By : Adam Ruppe
Book Image

D Cookbook

By: Adam Ruppe

Overview of this book

Table of Contents (21 chapters)
D Cookbook
Credits
Foreword
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

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:

  1. Create an additional file.

  2. 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;;;
  3. 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 the module statement in the file being imported, as shown in the following code:

    import yourpackage.yourmodulename;
  4. Use the functions, disambiguating with the full module name if required.

  5. Compile with all files listed on the command line using the following syntax:

    dmd file1.d file2.d
  6. 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