Libraries and Modules ===================== As you create a program, you will often discover subsets of your code that are candidates for sharing, reuse, or resale. Alternatively, you may be working on a large program that has been divided into pieces that can be implemented separately, either to allow parallel development, or to make the programming task more manageable. For either of these reasons, you can package your code into a *reusable software component* so that - Other programmers can easily add your component to their programs (which are called *client programs* of your component). - You can develop your component independently from any clients. - Clients can use your code without knowing or depending on the internal implementation of your component. - You can sell your component to clients without revealing your source code. Two important principles of software engineering apply here: information hiding and protocols. The principle of *information hiding* says that you should try to minimize the information that is passed between components in a system, thus minimizing the interdependencies of components. A *protocol* is the interface definition of a software component. The purpose of establishing protocols is to define a uniform interface that clients can use, even if the implementation of a component is enhanced or modified. Dylan supports software components, information hiding, and protocols in terms of *libraries* and *modules*. Many Dylan environments support simple or exploratory programming with a ``dylan-user`` module that includes both the standard Dylan language facilities and a common subset of Dylan libraries. Because all but the simplest programs usually grow into projects or are reused in new projects, it is good practice to create a unique library and module for each program or component. If you are writing a simple, stand-alone program or a simple component, you can use the simple library and module structure illustrated in :ref:`start-complete-program`. You may want to skim this chapter, however, so you have an idea of the options available for more complex situations. In this chapter, we start by describing the basic concepts of libraries (`Libraries`_), modules and namespaces ( `Modules`_), and programs and source records (`Source code, modules, and libraries`_). In the remainder of the chapter, we illustrate the concepts of libraries and modules by considering the classes and methods for times that we defined in :doc:`time-code`, and showing how they might be packaged into a reusable software component or library. We also show how the ``sixty-unit`` classes and methods could be a component substrate that the ``time`` library uses and shares with an ``angle`` library. Finally, we illustrate how to implement a ``say`` protocol that works with either or both of the ``time`` and ``angle`` libraries by creating a separate library that defines the shared protocol. Libraries --------- A Dylan library defines a software component — a separately compilable unit that can be either a stand-alone program or a component (library) of some larger program. The elements of the core Dylan language are in a library called ``dylan``. The simplest Dylan program consists of at least two libraries: the original program source in the program library, and the ``dylan`` library, which supplies the predefined Dylan language elements used by the program library. A simple Dylan component may consist of only a single library — the component library. The component library will be used by other libraries. The component library will use definitions from the ``dylan`` library (and possibly other components). Hence, when combined with other components into a complete program, the program will consist of several libraries. In each Dylan implementation, a library is associated with implementation-specific export information that is automatically maintained by the compiler. The library export information completely describes whatever implementation-specific information is needed for other software components to use the library. Thus, you can use libraries to deliver components in compiled form, keeping the implementation of the library confidential. .. topic:: Comparison with C++ and Modula: Dylan libraries are similar to C++ libraries in that they both are potentially shared components of many programs. Unlike C++ libraries, Dylan libraries include all the information needed to be used by another Dylan library — there is no companion header file that must be kept up to date. Dylan libraries are analogous to Modula packages — all the information necessary to use a library is contained in the library. .. _libraries-modules: Modules ------- A library is made up of modules, which hold the definitions of the library. Each module specifies an independent *namespace* for Dylan constants and variables. Each module can use definitions from other modules in the same library or in other libraries, and each module can provide definitions to other modules in the same or in other libraries. Each module controls the visibility of the names within a module from outside the module. You can use modules both to do information hiding and to prevent name clashes between constants and variables. Namespaces ~~~~~~~~~~ We mentioned in :ref:`start-variables-constants`, that Dylan has module variables and module constants. Every module contains its own set of module variables and constants. Two independent modules ``a`` and ``b`` might both have variables named ``*x*``. These are two different variables with possibly different values. Within module ``a``, a reference to module variable ``*x*`` is a reference to ``a`` ’s variable ``*x*``. Within module ``b``, a reference to module variable ``*x*`` is a reference to ``b`` ’s variable ``*x*``. In this sense, a module defines its own namespace. Definitions ~~~~~~~~~~~ A module variable or module constant is declared and initialized by a *definition*. We have already seen that ``define variable`` is a definition that establishes a module variable, and ``define constant`` is a definition that establishes a module constant. Dylan also uses module constants to refer to classes, generic functions, and macros. The definition for a class, ``define class``, establishes a module constant whose name is the class name and whose value is the class object. Similarly, the definitions for a generic function and a macro establish module constants. When we say that a module contains definitions, we mean that the classes, generic functions, macros, and other objects defined in that module are the values of variables and constants in that module. Export and import of names by modules ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Within each module, every name refers either to a definition owned by that module, or possibly to a definition owned by another module. Modules make the names of their definitions available to other modules by *exporting* those names. A module can refer to the names of another module by *using* the other module. Note that no module can access a definition in another module that is not exported; hence, modules provide a form of access control. When a module exports its names and a second module uses the first module, importing the names of the first module, then the definitions of the second module can use the names of the first module, just as they can use any other name in their own module. When one module uses a second module, it can use all the names exported from the second module, or it can specify a subset of those exports to *import*. In addition, imported names can be *renamed* — they can be given different names when imported. You can use renaming to document which definitions are from another module, by giving them all a uniform prefix; you can use renaming to resolve name conflicts; or you can use renaming to give nicknames or shorthand names for imported names. .. topic:: Comparison with C: Exported variables in Dylan are like external variables and functions in C. (By *external*, we do not mean the ``extern`` storage declaration, but rather the concept of an external variable — one that is available for linking to.) Unexported variables in Dylan are like *static* variables and functions in C. .. topic:: Comparison with C++: Dylan modules are similar to C++ namespaces in that they eliminate the problem of global namespace pollution or clashes between names used in individual libraries. Unlike C++ namespaces, Dylan modules also define a level of access control: Each module decides what names are externally visible, and no module can create or access names in another module, unless that other module explicitly exports those names. In contrast, the C++ *using* declaration allows the client of a namespace to access any name in that namespace. Export and import of modules by libraries ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Just as a module specifies a namespace for definitions, each library specifies an independent namespace of modules and controls the visibility of its modules. Within each library, every module refers either to a module owned by that library, or to a module owned by another library. Libraries make their modules available to other libraries by *exporting* those modules. A library can refer to the modules of another library by *using* the other library. No library can refer to the modules of another library that are not exported. When a library exports a module and a second library uses the first library, importing its modules, then the modules of the second library can use the modules of the first library, just as they can use any other modules in their own library. When one library uses another library, it can use all the modules exported from the second library, or it can specify a subset of those exports to *import*. Imported modules can be *renamed* as they are imported, just as imported module names can be removed. You can see that libraries and modules together provide a two-level structure of naming, information hiding, and access control. The designers of Dylan believed that only a single level would not give sufficient flexibility, but that more than two levels was unnecessary. In essence, modules give a fine level of control that lets you organize within a single component, and libraries give a higher level of control that lets you organize components into a program. Also, libraries are the Dylan *compilation unit* — they are the level at which components can be exchanged without source code being exchanged. A software publisher would typically sell its wares as Dylan libraries. Simple example of libraries and modules ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To illustrate these concepts, we repeat the definition of the ``library.dylan`` file, first shown in :doc:`start`. Here, we have used a more verbose, but also more precise, format. The library file: ``library.dylan``. .. code-block:: dylan module: dylan-user define library hello use dylan, import: { dylan }; use format-out, import: { format-out }; end library hello; define module hello use dylan, import: all; use format-out, import: all; end module hello; The first line of ``library.dylan`` states that the expressions and definitions in this file are in the ``dylan-user`` module. In this predefined module, you define the modules and library that make up your component or program. Every library has a unique ``dylan-user`` module. In the file ``library.dylan``, we define a library named ``hello`` and a module named ``hello``. The module definition names the other modules whose names the ``hello`` module will use. In this case, the ``hello`` module uses the ``dylan`` and ``format-out`` modules. Here, we have explicitly stated that we are importing all the names from the modules that we use — using the ``import: all`` clause is not strictly necessary, because it is the default that is used if we do not specify what to import. By using another module, we import the names exported from that module, making them available in our namespace. For example, ``format-out`` is exported from the ``format-out`` module, so the ``use format-out`` clause enables our program to call the ``format-out`` function. The ``use dylan`` clause in the module definition makes available all the built-in Dylan language elements exported from the ``dylan`` module. When we define a module, it must *use* all the modules that export the definitions used by the definitions in our module. The library definition tells the compiler which other libraries our program uses. Here, we have explicitly stated that we are interested in only the ``dylan`` and ``format-out`` modules from these other libraries. This clause is not strictly necessary, since the module definition tells the compiler which modules it uses; but it is good practice to document our intent. For example, the ``format-out`` module is in the ``format-out`` library. Therefore, our ``hello`` library must use the ``format-out`` library, and must import the ``format-out`` module for the ``hello`` module to use the ``format-out`` module. Similarly, the ``dylan`` module is in the ``dylan`` library, and therefore our ``hello`` library must use the ``dylan`` library and import the ``dylan`` module in order for the ``hello`` module to use the ``dylan`` module. When we define a library, it must *use* all the libraries that export the modules used by the modules in our library. The module definition also specifies which variables and constants are exported from the module for use by other modules. The library definition specifies which modules are exported from the library for use by other libraries. In our simple example, the ``hello`` module exports no variables or constants, and the ``hello`` library exports no modules. :ref:`Libraries and modules ` illustrates the relationships between libraries and modules in our example program. In :ref:`Libraries and modules `, and in the other figures in this chapter, we draw libraries as heavy bold boxes and modules as light boxes. We have tried to illustrate how libraries and modules build on one another through their “use” relationships. A library that uses another library is shown above the library that it uses, so we show the ``hello`` library above the ``format-out`` and ``dylan`` libraries. An exported module is illustrated as being on top of (overlapping) the library that .. _libraries-and-modules: .. figure:: images/figure-13-1.png :align: center Libraries (heavy boxes) and modules (light boxes) in “Hello, world”. exports it (we have also shaded them, to illustrate this overlap). And a module that uses another module is illustrated as being on top of (overlapping) the used module. Try to envision the modules as semitransparent overlays, layered up from the surface of the paper. Thus, the ``hello`` module overlays the ``format-out`` and ``dylan`` modules that it uses. Note that we intentionally do not show all the modules in the ``format-out`` and ``dylan`` libraries in :ref:`Libraries and modules `,. The ``format-out`` and ``dylan`` libraries might well have other modules, but either those modules are not exported or our program does not use them. Source code, modules, and libraries ----------------------------------- How is Dylan source code associated with modules and libraries? In Sections `Libraries`_ and `Modules`_, we looked at a Dylan program from the top down: A program contains libraries; a library contains modules; and a module contains variables and their definitions. We now look at a program from the bottom up, to see how source code is organized into modules, modules into libraries, and libraries into programs. Source records and modules ~~~~~~~~~~~~~~~~~~~~~~~~~~ All the Dylan source code for a program is organized into units called *source records*. How source records are stored is dependent on the implementation. Some implementations may store source records in a database, others may simply use *interchange format* files (see `Interchange files`_). No matter how they are stored, each source record is in a module; therefore, - All the module’s variables and constants, including those imported by using other modules, are visible to, and can be used by, the code in the source record. - The module controls which definitions in the source record are exported, and therefore are visible, to other modules. - Variables and constants in other modules that are not exported, or ones that are exported but are not imported by the source record’s module, are not visible to the source record. Dylan implementations can associate a source record with a module in different ways. The interchange format has a *header* at the front that specifies the module for its source records. Modules and libraries ~~~~~~~~~~~~~~~~~~~~~ Every module is in a library; therefore, - All the library’s modules, including those imported by using other libraries, are visible to, and can be used by, the module. - The library controls whether the module is exported, and therefore is visible, to other libraries. - Modules in other libraries that are not exported, or ones that are exported but are not imported by the module’s library, are not visible to the module. Dylan implementations can associate a module with a library in different ways. The *library-interchange definition* (*LID)* format lists the interchange files that make up a library. The module definitions in those interchange files are thus in that library. Libraries and programs ~~~~~~~~~~~~~~~~~~~~~~ Every library is in a set of libraries that can be combined into a program; therefore, - The library can import the exported modules of any other available library. - The library’s exported modules are visible to, and can be imported by, other available libraries. The Dylan implementation determines what libraries are available; how they are combined into a program; and how they are compiled, linked, and run. Consult your implementation documentation for further information. We have presented a simple hierarchical model: All Dylan code resides in source records; every source record resides in a module; every module resides in a library. Every module must be completely defined within its library, because the library is the Dylan unit of compilation. So that this restriction is enforced, every source record in a library must be in a module that is defined in the library; no source record can be in a module that is imported by the library. Within a library, it is possible for a name to be owned by one module and for that name’s definition to be provided by another module. This flexibility helps us to structure code, as we shall see in `Module definition`_. Module definition ----------------- Enough theory. Let’s see how modules and libraries can be used in practice by considering the classes and methods for representing and manipulating times that we defined in :doc:`time-code`, and showing how they might be packaged into a reusable software component. First, let’s examine what the external protocol of our time library might be. We have defined two kinds of time that can be created: ```` and ````. We have a generic function for printing times, ``say``, and one, perhaps not so obvious, utility function for creating new times, ``encode-total-seconds``. We define a method, ``\+``, for adding times, but a method is not a protocol. The protocol for the generic function ``\+`` is defined by the Dylan library, which already exports it, for any Dylan program. When we define our method for adding times, we are extending that protocol; we are not creating a new one. The ``decode-total-seconds`` function, the ```` class, and several other functions are used internally only, so they are not part of the external protocol. Although ``