Reconciling Subtyping and Code Reuse in Object-Oriented Languages: Using Inherit and Insert in Smarteiffel, the GNU Eiffel Compiler

Reconciling Subtyping and Code Reuse in Object-Oriented Languages: Using Inherit and Insert in Smarteiffel, the GNU Eiffel Compiler

Reconciling Subtyping and Code Reuse in Object-Oriented Languages: Using inherit and insert in SmartEiffel, The GNU Eiffel Compiler. Dominique Colnet1 Guillem Marpons2 and Frederic Merizen1 1 LORIA (UMR 7503 CNRS-INPL-INRIA-Nancy2-UHP) - France, [email protected], [email protected] 2 Universitat Polit`ecnica de Catalunya (UPC) - Spain, [email protected] Abstract SmartEiffel has been enjoying two different mechanisms to ex- press subtyping and implementation inheritance for one year. After large scale practical tests and thanks to user feedback, this paper finalises the new typing policy of SmartEiffel, which combines two forms of multi- ple inheritance with genericity in one statically-checked, object-oriented language. Having two forms of inheritance allows the designer to capture more design decisions in the source code. It is now straightforward to share reusable code between otherwise unrelated types. The new mechanism allows to reuse code from an existing class without polluting the reuser’s interface. It also enables an elegant implementation of some design pat- terns. Furthermore this mechanism helps compilers to statically remove more dynamic dispatch code. It can also be used to add a no-penalty and no- risk multiple-inheritance-like construct to a single-inheritance language such as Java. 1 Introduction The Eiffel language is intended to favour good software engineering practises. Its concern about building reusable software artifacts [10] should be stressed as the most salient trend of its design. The inheritance mechanism, in particular, was conceived as a powerful reuse mechanism with a panoply of adaptation facilities for inherited methods and attributes, and the possibility of multiple inheritance. Still, subclassing and subtyping are strongly coupled in traditional Eiffel. Reusing code through inheritance is desirable for the great flexibility it provides and because of performance considerations. In spite of this, enforcing a subtyping relation when inheriting has a number of drawbacks. The problem is obviously not specific to the Eiffel world [3] and this coupling sometimes produces flawed designs (examples in section 4). The designers always have to balance these disadvantages with the hindrance of reusing code through other means than inheritance, or even not reusing code at all—the worst being copy-pasting. In fact, the designers of Eiffel have recognised this conflict, slightly relaxing the subclassing/subtyping relation. This has been done by allowing argument types to be covariantly redefined and method visibility to be restricted in subclasses, leading to the well-known type-safety problems of the language [11]. The SmartEiffel team 3 has been working on Eiffel tools, compilers and li- braries for more than ten years [1,2,12,16,17]. In the remainder of this paper, we will use the unqualified term “Eiffel” as a shorthand for “the Eiffel dialect of the SmartEiffel team” 4. This paper discusses an implementation-only inher- itance language construct that we introduced in February 2005 (release 2.1 of the SmartEiffel compiler). This mechanism is conceived as a complement to the traditional Eiffel inheritance and gives the designer full control about which sub- typing relations are actually established. To avoid confusion we use the terms inheritance or inheritance mechanism for the traditional Eiffel inheritance, and insertion or insertion mechanism for the recently devised language construct 5. Since we first introduced the insertion mechanism, we have had the opportu- nity to extensively put it to use, on large scale programs and libraries, and with the feed-back of many SmartEiffel users. Thus, this paper is not only an aca- demic research work but also a practical report. Practising the mechanism has helped us to clarify ideas about what kind of type-system we need to best fit the new mechanism into the language. SmartEiffel currently implements the type- checking rules presented here, with one restriction regarding expanded classes that will be lifted in the next release (SmartEiffel 2.3). We refactored SmartEif- fel’s 450 standard library classes to exercise the insertion mechanism, and the classes now make use of 350 inherit links and 300 insert links. Our work on the li- brary clearly indicates that the new language construct favours the reconciliation between subtyping, static checking and reusability. The paper is organised as follows. Section 2 introduces the insertion mech- anism and some necessary background about Eiffel. The new typing policy is presented in section 3. Examples of how the insertion and inheritance mecha- nisms can be used together to remove certain specific design flaws and improve reuse opportunities are presented in section 4. Section 5 compares our work with papers or existing languages with similar aims. Section 6 concludes. 2 Adding the insertion mechanism to Eiffel Eiffel is an object-oriented language that features multiple inheritance, static typing, (constrained) genericity and design by contract. As in Smalltalk [6] even 3 All authors of this paper are members of the current SmartEiffel team. This paper can be considered as the work of the whole SmartEiffel team. 4 The reader might be aware that there are several dialects of the Eiffel language. The SmartEiffel dialect shares a common root with the ecma standardisation attempt [4] but diverged from it in May 2005. Since then, SmartEiffel has made its own way. 5 This mechanism has been known to Eiffel users as non-conforming inheritance. Legend: A Full listing of the inherit relationship: Inherits B inherits from A D inherits from A D inherits from B C Inserts B D inherits from C E inherits from C F inherits from A Full listing of the insert D E relationship: C inserts A E inserts A F inserts B F F inserts C F inserts D Figure 1. The inherit and the insert relationships on a non-trivial example. basic entities such as small integers are true objects of some existing class. Uni- formity in the type system helps to keep the language simple and to make all those facilities as broadly appliccable as possible. The language is well-suited for large software projects and teams. 2.1 Keeping inherit and adding insert The traditional inheritance mechanism introduced from the very beginning of Eiffel is still present and unchanged. The inheritance relationship both induces a subtyping relationship and introduces code reuse. The classes that a class inherits from constitute a list of zero, one or more elements called the inherit list of that class. Syntactically, the inherit list is introduced by the inherit keyword if non-empty. In the remainder of this paper, “A inherits from B” means that a path using only inherit links exists from A to B. Saying “A inherits directly from B” means that B is syntactically a member of the inherit list of A. In the new Eiffel syntax, a class can also have a second parent list introduced by the new insert keyword. This is the relationship to be used when code has to be inserted just for implementation purpose. The insert list can syntactically have zero, one or more parents. In the remainder of this paper, “A inserts B” means that a path using insert or inherit links exists from A to B, but A does not inherit from B (i.e. at least one insertion link exists from A to B in every path). The sum of the inheritance graph and the insertion graph must be an acyclic directed graph. Saying “A inserts directly B” means that B is syntactically a member of the insert list of A. Figure 1 summarises the inheritance and insertion relationships on a nontrivial example. The idea behind the insertion mechanism is simple: to complement the tradi- tional inheritance mechanism with a new one that keeps the code reuse aspects but discards the subtyping relationship. As we will see in the section 3, the fact that A inserts B does not allow us to assign an expression of type A into some variable of type B. For such a polymorphic assignment to be legal, A must be a subtype of B which can also be expressed as “A inherits from B”. 2.2 The special status of the any class There is a special class in Eiffel, named any, somehow comparable with Java’s Object class, that has been traditionally seen as the universal ancestor of the inheritance graph. A special rule still exists for class any, but now that we have added the new insert relationship, the status of any is slightly different. Class any is the only class that has no direct ancestor at all: both its inherit list and its insert list are empty. All other classes must have at least one direct ancestor either through the inherit list or through the insert list. Class any is now the final ancestor of the inheritance / insertion graph. As a consequence, if a class x is not the any class itself, then x either inherits from or inserts any. Actually, the any class contains important methods that all classes must have at runtime, including code necessary for object comparison, cloning and introspection support. Thanks to the rules we have just presented, we are sure that this code is part of all Eiffel classes. 2.3 Runtime requirements We do not only want a language dedicated to software engineering and specifi- cation, we also want Eiffel to keep the potential efficiency one can expect from a low-level language such as the C language6. A simple integer addition must be as efficient in Eiffel as in C. In Eiffel’s runtime model, this goal is achieved by having two kinds of classes: normal classes and expanded classes. Expanded objects are the instances of expanded classes. Most classes are normal (non-expanded). Normal objects are handled through a reference.

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    14 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us