This site contains older material on Eiffel. For the main Eiffel page, see http://www.eiffel.com.

Dynamic Linking in Eiffel

1 INTRODUCTION: THE DLE AND ITS PURPOSE

This document describes the specification for a mechanism, called Dynamic Linking in Eiffel or DLE for short, enabling developers of Eiffel software to defer until execution time certain decisions which they would otherwise have to make before compilation.

A system relying on the DLE mechanism may rely on one or more classes that were not known when the system was assembled, requiring the system to obtain the class descriptions from files at execution time.

The DLE brings to Eiffel a set of capabilities heretofore available only in completely dynamic approaches to object-oriented computation such as Smalltalk. This advantage -- the ability to reconfigure a system dynamically -- is achieved in Smalltalk at a heavy price in safety and efficiency, since it implies the absence of static typing (hence raising the possibility of run-time errors) and the inability to generate fully compiled code. The structure of Eiffel makes it possible to keep most of the advantages of a typed approach, and to bring the performance overhead down to an acceptable level.

A point of terminology: this document uses the term "developer" to denote a user of the DLE system -- that is to say a developer of Eiffel software who needs the DLE facilities.

The following section presents the overall picture by describing how developers will prepare a system for use with the DLE mechanism, and then use this mechanism. The rest of the report presents the details of the mechanism.

2 THE GENERAL DLE SCHEME

Using the DLE makes it possible to obtain a dynamically extendible system according to the following general sequence of developer actions.

  1. Developers produce a DLE-Ready System (or DR-system for short). A DR-system is in most respects a normal Eiffel system; in particular it must be self-complete, meaning that any class which the system's root needs directly or indirectly must be present in the system. What distinguishes a DR-system is that it may contain, in one or more places, an instruction intended to load a class description at run time. The system may then rely on that class description to create objects of the corresponding type and apply features to them.

  2. The developers assemble the DR-system (that is to say prepare it for execution through compilation and, if required, linking). The DR-system will have an Ace entry specifying that it is dynamically extendible. (A system's Ace, or Assembly of Classes in Eiffel, is the specification that guides assembly. The notation for writing Aces is called Lace.)

  3. At this stage the system is executable, although any execution of a feature that tries to perform a dynamic class load will fail, since no dynamically loadable class has been prepared yet.

  4. Developers (the same as in previous steps, or others) write a Dynamic Class Set or DC-set, that is to say one or more classes which may only depend on each other and on classes in the DR-system.

  5. The developers compile the DC-set. This form of compilation, relative to the DR-system, produces files containing descriptions of one or more dynamically loadable classes.

  6. It is now possible to run the DR-system so that its execution will use the dynamically loadable classes stored in the files produced at step 5.

Steps 4 to 6 may be repeated as many times as needed.

The DLE mechanism does not make any assumption about the compiling mode used to assemble the DR-system and the DC-set, which may be any of the three compiling modes of ISE Eiffel: melting, freezing and finalizing. Compilation may be started from either the graphical environment (EiffelBench) or the command-line tool (es4).

The following sections examine in more detail the actions needed in the above steps.

3 USING DYNAMIC CLASSES

The first step in using the DLE mechanism is to prepare a DR-system.

3.1 Preparing the Ace

A DR-system is characterized by a line of the following form in the default paragraph of its Ace:

extendible (yes)

Including this option directs the Eiffel compilation process to generate code that is ready for the insertion of extra classes at run-time. There is no limit on the number of classes that may be added dynamically.

The precise definition of a DR-system used in the rest of this Report is that it is a system whose Ace includes an entry of the above form. A no value is permitted, but has the same effect as if the Ace did not include an extendible entry.

The classes that are part of the DR-system at the time of its assembly will be called static classes.

If you have assembled a DR-system, the DLE mechanism allows you dynamically to add to it not just classes but also features.

3.2 Taking advantage of the DLE mechanism

A DR-system is able to incorporate classes compiled after the system's assembly, also called dynamic classes. Of course this capability will only be useful if the system includes dynamic operations, that is to say operations that use the dynamic classes, and if at least some of the dynamic operations appear in static classes. This creates an apparent paradox since the classes on which dynamic operations rely are not known at assembly time.

Here is the way it works. The DR-system may rely on two library classes: DYNAMIC and DYNAMIC_CLASS, with the following goals:

  • DYNAMIC describes the property of being dynamically loadable. Any dynamic class -- that is to say, any class added to the system after assembly -- must be a descendant of DYNAMIC. Instances of DYNAMIC and its descendants are called dynamic objects.

  • DYNAMIC_CLASS describes classes that may be dynamically loaded. An instance of DYNAMIC_CLASS is a class description; such a description can be retrieved from a file in the same way as Eiffel's STORABLE mechanism.

Note the difference between DYNAMIC and DYNAMIC_CLASS, suggested by the names. An instance of DYNAMIC is an object -- an instance of a dynamic class. An instance of DYNAMIC_CLASS describes a class (one of the dynamic classes themselves).

3.3 Retrieving dynamic classes

To use a dynamic class a DR-system will need, at execution time, to obtain a description of that class, in the form of an instance of class DYNAMIC_CLASS.

Assume that (using the process explained in section 6) you have compiled a dynamic class with respect to the DR-system. The result is a class description, in the form of an instance of DYNAMIC_CLASS which the compilation has stored in the directory associated with a DC-set. To retrieve that instance, you may use the following creation procedure of class DYNAMIC_CLASS:

    make (class_name, dc_dir: STRING)
            --  Initialize to representation of dynamic class of name class_name
            --  in the DC-set whose directory is dc_dir.
            --  Set retrieve_status to non-zero value if no such class can be found.
        require
            class_name_exists: class_name /= Void
            class_name_not_empty: not class_namelempty
            DC_set_path_exists: dc_dir /= Void
            DC_set_path_not_empty: not dc_dir.empty

The second argument, dc_dir, is the project directory that has been used to assemble the set of dynamic classes, or DC-set, to which the requested dynamic class class_name belongs. Section 6 explains the notion of DC-set and shows how to assemble a DC-set.

To find out whether the make creation procedure has been able to produce a useful class description, you may use the query retrieve_failed. The following cases will prevent the procedure from yielding a class description; in each of them it will set the result of the query retrieve_status to the value of an integer constant as indicated:

  • dc_dir is not the name of a directory containing the proper information about a DC-set. Error value: Bad_DC_directory.

  • No dynamic class exists for class_name in the DC-set. Error value: No_dynamic_class.

  • The directory dc_dir exists but the corresponding file cannot be read. Error value: Unreadable_file.

  • There is such a class and it can be read but it is not a descendant of DYNAMIC. Error value: Bad_class.

  • The retrieved class has the same name as a previously retrieved dynamic class. (This error is possible because a system can use two or more DC-sets.) Error value: Duplicate_class_name.

Procedure make of DYNAMIC_CLASS, in addition to being a creation procedure, is exported, so that it may be called again on an instance of this class after creation -- for example after one of the above error codes has been detected.

3.4 Producing instances of dynamic classes

Having obtained an object representing a dynamic class, you may use it to produce instances of that class -- dynamic objects. To obtain a dynamic object, the DR-system will use the following function from DYNAMIC_CLASS:

    instance: DYNAMIC
             --  An instance of the class represented by current object,
             -- initialized by procedure make of that class, using
             -- argument as argument
        require
            class_exists: not retrieve_failed
        ensure
            instance_not_void: Result /= Void

Class DYNAMIC has a procedure called make, which expects a single argument of type ANY. Every proper descendant of DYNAMIC should also have such a make procedure to perform any necessary initialization, and should include it in its Creation clause. Class DYNAMIC_CLASS provides a procedure to specify the argument that will be passed to instance:

    set_argument (val: like argument)
             --  Define val to be the argument to be passed to creation procedures
             --  by subsequent calls to instance.
         ensure
            argument_set: argument = val
    

The value last set by set_argument is accessible through feature argument of DYNAMIC_CLASS, of type ANY.

Assume that class YOUR_DYNAMIC is such a descendant of DYNAMIC, entity your_object has been declared of type YOUR_DYNAMIC, entity your_class_description is attached to an instance of DYNAMIC_CLASS that describes a certain class YOUR_CLASS, and your_argument denotes some value to be used as argument to the intended creation procedure. Then the effect of the instructions

[1]
    your_class_description.set_argument (your_argument);
    your_object ?= your_class_description.instance

is the same that would normally be obtained, were YOUR_CLASS a static class belonging to the DR-system, through the creation instruction

[2]
    !YOUR_CLASS! your_object.make (your_argument)

3.5 The overall scheme

As a result of the preceding discussion the normal scheme for using a dynamic class is the following.

This extract assumes that you have declared a class YOUR_DYNAMIC as a descendant of DYNAMIC, and that the dynamic class YOUR_CLASS has itself been declared as a descendant of YOUR_DYNAMIC.

    your_class_description: DYNAMIC_CLASS;
    your_object: YOUR_DYNAMIC;
    your_argument: YOUR_ARGUMENT_TYPE;
    ...
    create your_class_description.make ("YOUR_CLASS", "your_directory_name");
    if not your_class_description.retrieve_failed then
            -- As above:
        your_class_description.set_argument (your_argument);
        your_object ?= your_class_description.instance
    end;
    if your_object /= Void then
        your_object.some_feature (...)
    end

Here some_feature is a feature of class YOUR_DYNAMIC. In the most interesting cases the dynamic class retrieved by the call to make will redeclare that feature, so that with dynamic binding the call your_objectlsome_feature (...) will trigger a feature variant that was not known at the time the DR-system was assembled.

In spite of their names DYNAMIC and YOUR_DYNAMIC are static classes since they are part of the DR-system at assembly time; they are static specifications of the minimum set of properties of dynamic classes.

4 USING DYNAMIC FEATURES

(This section currently not included.)

5 A SUMMARY OF LIBRARY CLASSES AND FEATURES

The DLE mechanism is supported by a library (the DLE library) whose classes and features have been introduced in the preceding sections. The complete list of these classes and features appears in appendix B.

6 PRODUCING DYNAMIC CLASSES

Once you have a DR-system you may add dynamic classes and features.

To produce dynamic classes you will prepare a Dynamic Class Set or DC-set. A DC-set is similar to a system, and will be assembled as a system, with the peculiarity that its classes are permitted to depend not just on each other but also on a previously assembled DR-system, called the base system of the DC-set. (The dependencies considered here are the two kinds of class dependency permitted in Eiffel: client and inheritance.)

You will prepare a DC-set the way you would prepare a normal system, with only one specific requirement: the Ace of the DC-set system must contain, in its default paragraph, an entry of the form

    extending ("dr_dir")

where dr_dir is the project directory of its base system. (As a convension the root paragraph will repeat what has been specified for the DR-system.) A system is considered to be a DC-set if and only if its Ace contains such an entry with a non-empty dr_dir string.

A few restrictions apply to a DC-set. The assembly of a DC-set will only succeed if a system obtained by merging the DC-set and its base system could be assembled successfully. This implies the first two of the following four restrictions:

  1. If a class of the DC-set depends on a class C, then C must be either in the DC-set or in the base system.
    In the absence of class renaming in Lace, no class of the DC-set may have the same name as another class of either the DC-set or the base system.
    Every descendant class of DYNAMIC in the DC-set must have a creation procedure called make which expects a single argument of type ANY (validity code V9CP).
    No descendant class of DYNAMIC in the DC-set may be generic (validity code V9GC).

Restriction 4 is an implementation constraint. It is worth noting that there is no restriction on the size of the DC-set.

It is possible in principle (although not in the current release) to write more than one DC-set for the same base system, so that at run time a DR-system will be able to load dynamic classes from different DC-sets.

Successfully assembling a DC set will produce, in a subdirectory of its project directory, a set of files that contain descriptions of the dynamic classes. Such descriptions can then be retrieved by the DR-system during its execution, using the make creation procedure of class DYNAMIC_CLASS as explained in section 3.3.

7 IMPLEMENTATION CONSIDERATIONS

The major implementation issues arise for final mode. The principal question is how to store the representations of dynamic classes, as produced by the assembly of a DC-set and retrieved by the make procedure of DYNAMIC_CLASS.

Although it is possible to use an interpretive representation for dynamic classes, it seems preferable for performance reasons to go to C in final mode. This assumes that the platform supports a form of dynamic libraries. This is not the case with all platforms, but includes SunOS, Solaris, SGI, Windows and a few others. The current implementation under Solaris takes advantage of such facilities.

Also related to final mode, compilation optimizations provided by ISE Eiffel (dead code removal, inlining, array optimization and statically bound feature calls) are supported both in the DR-system and in the DC-set. An implementation problem arises, however, with respect to statically bound feature call optimizations. A feature call which was statically bound at the DR-system assembly time might not be valid anymore after loading a DC-set introducing a class which redefines this feature. A new free option has been introduced in the default and option clauses of the DR-system's Ace to provide the developer with additional control of this optimization mechanism:

    dynamic (f): CLASS1

Including this option directs the Eiffel compilation process to generate dynamically bound feature calls in the DR-system for feature f applied on objects of type CLASS1 even though these feature calls could have been statically bound at that time. For convenience, the following forms are also permitted:

dynamic (f): CLASS1, CLASS2;
dynamic (all): CLASS1;
dynamic (all): CLASS1, CLASS2

Since in most interesting cases descendant classes of DYNAMIC will redefine features inherited from the static classes, calls to these features will all be automatically bound dynamically.

Also for convenience, the compilation of the DR-system in final mode generates in file EIFGEN/F_code/STATIC the list of feature calls that have been statically bound.

8 ADDITIONAL CONSTRAINTS

The following requirements are imposed on the use of the DLE mechanism:

  1. The base DR-system must be stable during the development of a DC-set. The DC-set will have to be recompiled from scratch after any recompilation of its base system.
    At execution time, the DR-system and DC-set must either be both in workbench mode (melted or frozen) or both in final mode.

  2. A DC-set may only be finalized if its DR-system has been finalized (validity code V9FM).

  3. One cannot change the extendible property of a system between two compilations, unless recompiling it from scratch (validity code V9CD).

  4. One cannot change the extending property of a system between two compilations, unless recompiling it from scratch (validity code V9CX).

  5. It is not possible to apply the debugging facilities (setting and removing stop points) to routines of a dynamic class.

9 RESTRICTIONS

The preceding sections have described the full mechanism. The current version of the DLE mechanism imposes an additional restriction: at most one DC-set may be used per DR-system. Trying to load more than one DC-set will set retrieve_status to the integer constant value Duplicate_DC_set.

The current DLE implementation is available on Solaris. Please inquire with ISE about ports to other platforms.

Table of Contents Next Chapter