Adaptation by Inheritance Technique PreviousNext

[Note that the examples used below to illustrate this adaptation technique may be out of date and not relevant anymore for recent versions of the supported Eiffel compilers.]

NICE (Nonprofit International Consortium for Eiffel) has provided us with a kernel library standard that we can rely on for interoperability between Eiffel compilers. This standard is made up of a set of classes, such as ANY, INTEGER or STRING, and a set of features that all Eiffel compilers should implement. However, some compilers fail to support some these classes or features, making it difficult to write portable Eiffel code. Moreover, some useful features are also missing in the standard. Some compilers may provide implementation for these features, but some don't.

Description

One way to get around this problem without having to directly edit the library classes is to put a layer of classes between the kernel library and the application classes. In that layer, there will be a different cluster for each supported Eiffel compiler. Each such cluster will contain the same set of classes, each of these classes adapting a corresponding kernel class through inheritance. For example, ELKS '95 states that class PLATFORM among other things should have the two following features:

Minimum_character_code: INTEGER
        -- Smallest supported code for CHARACTER values
    ensure
        meaningful: Result <= 0

Maximum_character_code: INTEGER
        -- Largest supported code for CHARACTER values
    ensure
        meaningful: Result >= 127

However these two features were missing in class PLATFORM provided with ISE Eiffel 4.2 and Halstenbach 2.0. The solution to this problem is to use class KL_PLATFORM in the client code, where KL_PLATFORM had the following form in the clusters associated with ISE Eiffel and Halstenbach:

class KL_PLATFORM

inherit

    PLATFORM

feature -- Access

    Minimum_character_code: INTEGER = 0
    Maximum_character_code: INTEGER = 255
            -- Smallest and largest supported codes for CHARACTER values

end

and the following form in all other clusters:

class KL_PLATFORM

inherit

    PLATFORM

end

That way, a call to Minimum_character_code from a client of class KL_PLATFORM will always work, regardless of the Eiffel compiler used. This wouldn't be true for clients of PLATFORM.

This technique can also be used to supply missing classes. For example the class EXCEPTIONS was not provided in SmallEiffel -0.81. However this class is useful when a system has to be terminated using feature die. This routine could easily be implemented using SmallEiffel's built-in die_with_code feature. SmallEiffel kernel adaptation cluster hence ended up with the following class:

class KL_EXCEPTIONS

feature -- Basic operations

    die (a_code: INTEGER)
            -- Terminate execution with exit status a_code
            -- without triggering an exception.
        do
            die_with_code (a_code)
        end

end

whereas clusters for other compilers already supporting this facility contained this simple class:

class KL_EXCEPTIONS

inherit

    EXCEPTIONS

end

Sometimes, the required functionality will be provided but under another feature name or with an inefficient implementation. Once again one can in these situations inherit from the corresponding classes and rename or redefine the proper features. This is for example the case in class EXCEPTIONS from Halstenbach 2.0 where feature die was obsolete and feature new_die had to be used instead:

class KL_EXCEPTIONS

inherit

    EXCEPTIONS
        rename
            die as old_die,
            new_die as die
        end

end

Finally, some useful features are missing from the standard. For example class ARRAY is not equipped with a feature clear_all which would reset all items in the array to their default values. Some compilers already provide an efficient implementation of this routine, but some don't. When it is not already provided, it is easy to add this routine to the corresponding class KL_ARRAY.

Caveats

Although the technique described above seems attractive, it still has some drawbacks. One of these disadvantages is when using manifest constants. For the adaptation by inheritance solution to work properly, the application code should now always use the KL_ classes instead of the kernel classes they inherit from. But the following code:

my_string: KL_STRING
my_array: KL_ARRAY [INTEGER]
...
my_string := "Hello World!"
my_array := <<1, 2, 3>>

will not compile because "hello World!" is a STRING which does not conform to KL_STRING, and <<1,2,3>> is an ARRAY which does not conform to KL_ARRAY (although KL_STRING conforms to STRING and KL_ARRAY conforms to ARRAY). To solve this problem, one would then have to write:

create my_string.make_from_string ("Hello World!")
create my_array.make_from_array (<<1, 2, 3>>)

which is cumbersome and inefficient with some compilers.

Another problem encountered with this technique is that most Eiffel compilers do not support some of their kernel classes to be adapted using inheritance. This is for example the case for basic types such as INTEGER or CHARACTER, and also for some other classes such ARRAY or STRING where some built-in features hard-coded for optimization purposes cannot even be renamed in descendant classes without breaking the run-time system (try to rename feature count from class ARRAY in a descendant class with SmallEiffel to convince yourself).

Finally, the kernel library standard specifies that compatible implementations may provide more features than those required. This implies that using these classes by inheritance, as the technique described here does, the extra features will pollute the name space and might cause name clashes dependent on the Eiffel compiler used.

Another adaptation technique, using the client/supplier relationship, gets around these problems.


Copyright 1998-2016, Eric Bezault
mailto:
ericb@gobosoft.com
http:
//www.gobosoft.com
Last Updated: 23 December 2016

HomeTocPreviousNext