From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: fac41,2c6139ce13be9980 X-Google-Attributes: gidfac41,public X-Google-Thread: 103376,3d3f20d31be1c33a X-Google-Attributes: gid103376,public X-Google-Thread: f43e6,2c6139ce13be9980 X-Google-Attributes: gidf43e6,public X-Google-Thread: 1108a1,2c6139ce13be9980 X-Google-Attributes: gid1108a1,public From: Bertrand Meyer Subject: Re: Interface/Implementation (was Re: Design by Contract) Date: 1997/08/27 Message-ID: <34046FAD.52BFA1D7@eiffel.com> X-Deja-AN: 268629991 References: <33E9ADE9.4709@flash.net> <34023BC4.2781E494@eiffel.com> <3402d123.0@news.uni-ulm.de> <3402DA6A.C4444E46@calfp.co.uk> <3402e51d.0@news.uni-ulm.de> <3402E8C9.3384D976@calfp.co.uk> <3403F668.F6B57D97@calfp.co.uk> <34041331.0@news.uni-ulm.de> <3404696D.4487EB71@eiffel.com> Organization: Interactive Software Engineering Inc. Newsgroups: comp.object,comp.software-eng,comp.lang.ada,comp.lang.eiffel Date: 1997-08-27T00:00:00+00:00 List-Id: Here is the reasoning behind the Eiffel approach to separating interface from implementation. It was designed in full knowledge of the Modula-2/Ada-83 mechanisms, in an attempt to draw the lessons of both their advantages and limitations, taking advantage of newer software technology and of O-O principles. The goals are clear: G1. Allow people to consider separately the interface and the implementation of a module -- class in Eiffel, module in Modula, package in Ada. G2.(Closely related to G1.) Allow a developer to write a client class of a class C without knowing what C's implementation is, or even prior to the existence of such an implementation, as long as C's interface is known. G3 (Closely related to G2.) Allow a project leader to restrict the list of who can access the implementation of a module, allowing others access to the interface only. This is also of interest to vendors of reusable components, who may want to make source not available to their customers in some or all cases. (Whether this is good or bad is another topic; it is a fact that some vendors want this possibility.) G4. Allow multiple implementations of a given interface, including the possibility for clients to switch easily and implicitly between various implementations at run time (not possible, at least not possible simply, in Modula/Ada). This of course will take advantage of polymorphism and dynamic binding. G5. Minimize the programmer's work. In particular it is crucial to avoid forcing the programmer to duplicate text. Duplication is almost always bad, especially with respect to ease of maintenance, one of the central goals of software engineering. It also hampers reuse, reliability (when you duplicate code, you duplicate its bugs, and the more software you write the more likely it is that it will include bugs), and ease of change. G6. Favor seamlessness: the Eiffel method emphasizes the notion of a "single product" around which all software development activities revolve. This is in opposition to the traditional multi-product view ("the analysis", "the design", "the documentation", "the code" -- including ,for the latter, "the interface", "the implementation"). We may not always succeed in putting everything into one place (i.e. we will probably retain the need for some external documentation) but will try to get as close as possible to this goal; the benefits for the software process are enormous. The Eiffel policy is a result of these considerations: E1. If a class has a single implementation, write everything at the same place: interface and implementation. This directly addresses requirements G5 and G6 and differs markedly from the Modula, Ada etc. practice of writing the interface twice (once in the interface part, once in the body), which in my opinion is a nuisance, not just because of the initial duplication of work but because of the added maintenance burden. E2. Provide tools in the environment to produce the interface of a class, automatically from the class text. In Eiffel environments this is the role of the short and flat-short tools, which reconstruct the interface from the class. In ISE Eiffel you click on the "short" or "flat-short" icons of a Class Tool and the contents change to show the interface, pretty-printed, or in HTML format (with references to other classes turned into hyperlinks), RTF, FrameMaker etc. E3. A generalization of E2 follows from the observation that instead of just "implementation" and "interface" we should be talking about various *views* of a class, and rely on the power of the *computer* to produce these views as we need them. The implementation is one such view; the interface is another; but there are more. Short and flat-short are indeed examples of different abstract views (short considers only the features introduced in the class; flat-short integrates inherited features too). An environment can also provide many intermediate views, such as "the features available to a client class C" (i.e. the interface of the class as viewed by the author of C), "the interface as available to a descendant class", etc. This is only possible because we do NOT require the class author to write the interface separately; generalized, this idea would become absurd since it would mean that you have to write lots of different interfaces (views) for each class. Instead, the Eiffel view is that you should write the class -- the single product, see goal G6 -- and concentrate on equipping it with everything that it needs: useful features, complete preconditions, expressive postconditions, insightful class invariants, efficient implementations. You don't want to be bothered by e.g. having to write routine interfaces twice. Then if you or one of your client authors needs information about apecific properties of the class you will rely on tools to get it. Like many other differences with common languages, this Eiffel policy results from a difference of appreciation as to what should be done by humans and what by the computer. We want to let humans concentrate on creative, insightful work (e.g. designing a class), and rely on the computer for automatable and potentially tedious tasks. It is the same spirit that explains Eiffel's policy (in contrast variously with Ada, C++ etc.) with respect to dynamic binding, garbage collection, routine inlining (in the ISE implementation), etc. E4. There remains the case in which you do want to write the interface as a separate module, because it can have several implementations. The technique then is easy: write it as a deferred class; then the various implementations can inherit from it. But then it will truly deserve to be called a "specification" (the Ada term) because, unlike other languages, Eiffel makes it possible to attach true semantic properties to the components of a deferred class: routine preconditions, routine postconditions, class invariants. (This is missing from Ada "specifications" and Java "interfaces" and, in my opinion, regrettably limits their usefulness.) These specification elements are binding on all redeclarations in descendant classes ("effectings" in Eiffel terminology, i.e. a descendant providing an actual implementation for a feature that in the parent was deferred, i.e. specified but not implemented). E5. In case E4, it is of course possible to switch at run time between the various alternative implementations provided, thanks to polymorphism and dynamic binding. If I have t: TABLE [SOME_TYPE] where TABLE has various descendants providing alternative table implementations, I can write t.search (some element) without knowing what kind of table `t' denotes (although I know it can only be a table, thanks to the type rules). Then various executions of the call, including during the same session of the system, can refer to different implementations and consequently use different versions of `search', automatically selected by the dynamic binding mechanism so that they will always be the appropriate one in each case. E5. Sometimes you may start out with a concrete class of which you consider only one possible implementation (case E1), and hence not bother to write a separate deferred class. Then later you may realize that you need other implementations too. Then the switch to case E4 is easy: just use a "short"-like tool to produce a deferred class from the original and rewrite that original to inherit from the deferred class. This is an easy change and in particular is painless for the existing client classes, since they only relied on the interface (as produced by short or flat-short) and hence will not be affected at all by the change; they may not even have to be recompiled. This is a direct implementation of information hiding principles. E6. An Eiffel implementation may permit the author of a class library to make it available precompiled, without giving access to the source. (This is the case with ISE Eiffel 4.) The short and flat-short forms are of course available through the tools of the environment. This directly addresses goal G3. In short, the Eiffel approach proceeds from the same general ideas as the technique of "separating interface from implementation" but goes further; it considers the whole software engineering picture, takes into account the problems encountered with the Modula-Ada approach, and of course takes advantage of object technology. These issues are discussed in more detail in "Object-Oriented Software Construction, 2nd edition" (Prentice Hall); see in particular chapter 23, "Principles of Class Design", pages 747-808. -- Bertrand Meyer, President, ISE Inc. ISE Building, 2nd floor, 270 Storke Road, Goleta CA 93117 805-685-1006, fax 805-685-6869, http://www.eiffel.com, with instructions for download