/
jects while standing on one foot. jects while standing on one foot.

jects while standing on one foot. - PDF document

lindy-dunigan
lindy-dunigan . @lindy-dunigan
Follow
402 views
Uploaded On 2015-09-17

jects while standing on one foot. - PPT Presentation

EIFFEL T e x t A NoOverloading PrincipleDifferent things should have different names Bertrand Meyer is CTO of Interactive Software Engineering which just releasedISE Eiffel 50 the most important ID: 131789

EIFFEL T e t A No-Overloading PrincipleDifferent things

Share:

Link:

Embed:

Download Presentation from below link

Download Pdf The PPT/PDF document "jects while standing on one foot." is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.


Presentation Transcript

EIFFEL T e x t A jects while standing on one foot.Ó Rabbi Shammaiwhacked him on the head with a 10-by-2 ruler. He went to RabbiSome commentary now. The beauty of object technology(OT) is that for all the variations, refinements, codicils, and con-sequencesÑincluding fifteen years of the Journal of Object-Ori-ented ProgrammingarticlesÑeverything in the end rests on aÒmembersÓ in several other languages). In a class Enforcing a one-to-one correspondence keeps everythingfound what you are looking for, and do not need to worry aboutstatement of intent. Within a single syntactic scope such as a class,just choose different names.Why indeed give the same name to two different things? Namesare not an endangered species, and there is no tax on keystrokes.Even in Eiffel, where we like giving features clear, meaningful, pro-nounceable namesÑI have never been able to understand whyothers use or even when it is so simple to write, and say it loud when neededÑwe have endless pos-sibilities from words and their combinations. If it is two differentthings, call them by different names. Appending a character to astring, or concatenating another string at the end, are not the sameoperation by any stretch of imagination. Why pretend that theyare, and in the process confuse the poor program reader? Just useextend (c: CHARACTER)-- Add at end.= old + 1item (count)for adding a character, and(s: -- Concatenate characters of at end./= old + 1,), these are different operations. Features to concatenate the stringNote that this practice goes well with the rule, part of the Eif-feature, such as my_string.extend ('X'), the type of the target,Overloading vs. Object TBertrand Meyer No-Overloading PrincipleDifferent things should have different names. Bertrand Meyer is CTO of Interactive Software Engineering, which just releasedISE Eiffel 5.0, the most important new version since ISE Eiffel 3 in 1993.(http://www.eiffel.com). His latest book is The .NET Training Course Hall). He may be reached at Bertrand_Meyer@eiffel.com. www.joopmag.comOctober/November 2001Journal of Object-Oriented Programming3 E I F F E L The No-Overloading Principle (meaning that a class establishesa one-to-one correspondence between feature names and fea-tures) has a strong consequence on multiple inheritance: if aclass has two parents and , and both have a feature called, you canÕt leave things as they are; this would be as bad as in-troducing two features called in itself. The Eiffel techniquerelies on the observation that there is nothing wrong with and taken individually: each of them, to be valid, must haveprovided its one-to-one correspondence. There is also no prob-lem (in the absence of further complications, such as might result from repeated inheritance) if wants to inherit bothclasses and hence inherit both the features called : These aredifferent features; the only issue is an unfortunate naming con-flict. To resolve that issue, it suffices to rename one or both in-herited features, at the point of inheritance in . This is thewell-known technique of Eiffel:... The features specific to end Ð class Now, as a result, defines its own name-feature correspondence,one to one. The power of renaming extends beyond this case: itenables you to adapt the names of inherited features to the con-text of the new class. Even if a parentÕs feature is useful to theclients of , its name may not be the most appropriate for thoseclients, who see the feature in a different light, as part of the ab-straction represented by , not its parent. Each class is a machine,whose designer should have full power to define both the func-tionality (the features) that he deems most useful to the clients,and the exact form under which the clients will get that func-tionality, including names most appropriate to their needs. Re-naming helps the designer achieve that goal.Past the clauses, the inherited features are known inthe new classes under their new names. This leads to the notionof the final nameof a feature: its declared name if it is immedi-ate (introduced in the class itself); its original name if it is inher-ited and not renamed; the new name if it is inherited and renamed.Every reference to a feature of a class, from anywhere in the soft-ware text Ñthe featureÕs class, or anotherÑuses its final name.The designer will also, in some cases, want to change the in-herited features themselves. This is the purpose of redefinition:É New declaration of ... Features specific to Ð class Redefinition changes the feature, not its name. Renaming changesthe name, not the feature. In some cases youÕll want both:f1, gNote the use of the final name for the redefinition.This view ofeach class as a professional-quality machine under the precise con-trol of the machineÕs designer is central to the Eiffel method.WRONG CRITERIONWhat is puzzling in languages that support overloading is the cri-terion they use to distinguish competing features with the samenameÑthrough their type signatures. The rule is that it is legal togive two features the same name if and only if at least one of the ar-gument types differs. But that criterion is irrelevantÑtwo com-peting features may well have the same argument types. For ex-ample our class might have features that reset a pointÕs coordinates to given values. This isa typical situation where overloading, for people attracted to this idea,would seem appropriate. Unfortunately for them, even in such arudimentary example it doesnÕt work since the argument typeshappen to be the same in both cases: both and set_polar will take two arguments of type. The signature cri-terion has nothing to do here.In such a case you could in principle name the features differ- 4Journal of Object-Oriented ProgrammingOctober/November 2001www.joopmag.com ently, but C++ and its successors such as Java and C# donÕt leaveyou that possibility. In its overloading zeal, C++ forces you to giveall ÒconstructorsÓ of a classÑthe procedures used to initialize its in-stancesÑthe same name, which must be the name of the class.Calling everything the same certainly saves efforts of imagination,but the results are strange. In our example, would not onlybe the class name but also the name of all the constructor routines.How then do you offer alternative ways of creating a point, one byproviding the cartesian coordinates and one by providing the po-lar coordinates? You do not. It is just not possible. Here, over-loading appears not only as useless and potentially confusing, butas a facility that severely limits the power of expression of the lan-guage and prevents the use of commonly useful patterns.In Eiffel, of course, constructors (creation procedures) arenamed; you create an object through(1, 0)where is one of the procedures of the class, and islisted in the Creation clause at the beginning of the class:make_cartesian, make_polar, default_createÉ Declaration of features, including and Note that creation procedures such as and lar are otherwise normal procedures; by setting their export status,you can elect to have them usable for creation only, for resetting ofan existing object (playing the role of and as posited above), or both. Procedure is availablein all classes; you can redefine it in any class to override the defaultinitializations performed in procedure-less creations of the formformally understood as an abbreviation for If the class has no Creation clause, it is understood tohave one listing only , so that the basic form is permitted by default.I have briefly described this Eiffel mechanism, using namedcreation procedures, because it seems the obvious and simple thingto do. The reliance on overloaded non-named constructors is hardto justify.INTRODUCING INHERITANCEWith inheritance, the use of overloading appears even more con-fusing. Consider a simple pair of inheritance links (see Figure 1).We will use names reminiscent of the corresponding types. Inclass , feature is overloaded with two variants accepting argumentsof types and . LetÕs also assume that redefines (overrides)these versions. The following polymorphic assignments are possi-ble for of type of type and so on:a1 := b1x1 := y1Now consider the corresponding calls:a1.f (x1)a1.f (y1)b1.f (x1)b1.f (y1)In an OO environment, they should all give the same result, sinceand are both attached to the same object, and both attached to another single object; but overloading compli-cates everything. (If you program in a language with overloading,can you tellÑQuick! No textbooks! No language lawyers!Ñwhichvariants are permitted? What does each do?)Overloading simply does not go with inheritance and its as-sociated techniques of redefinition, polymorphism, and dynamicbinding. If you are happy to sacrifice inheritance, then you mayconsider overloading (as in Ada 83), although enough unpleasantconsequences remain that I would not advise following that route.But with OO techniques it becomes impossible. GOVERNMENT BY WARNINGTo see the consequences of the systematic reliance on overloadingand how it clashes with inheritance, consider the following mech-anism, known as Òversion management,Ó of C#.If a feature of a class has a name that conflicts with the name ofan inherited feature, it must normally be declared as either ÒÓ or Ò.Ó The first case is the normal OO mechanism of re-definition. The second is only possible because of overloading, andrequires that the argument signature be different from the signatureof the inherited version.So far so good, or rather (in light of the previous discussion)so far so bad. But now comes a special convention, designed to ad-dress the case of delivering to your customers a new version of aclass with a new feature called . That name was not used inprevious versions of so perhaps one of your customers had writ-ten a descendant class where he introduced a feature of his own,called . But now this name conflicts with that of an inherited fea- Figure 1. Overloading clashes with inheritance. www.joopmag.comOctober/November 2001Journal of Object-Oriented Programming5 ture. Since there is no direct equivalent of renaming, you should nor-mally go back to and change it to declareas . But then itmeans that does not work Òas isÓ any more. To facilitate the up-grading process, the language lets you omit any or specification, with the understanding that an absent specificationwill have the same effect as a declaration, and the requirementthat the compiler must produce a warning.This is disturbing. First, it is (at least as far as I know) a firstin the history of programming languages: the first case of defin-ing a languageÕs semantics through compiler warnings. Seman-tics should be defined very precisely, since it conditions the validityof programs and the effect of valid programs. The 70 or so Òva-lidity rulesÓ of Eiffel 1 are all of the form, ÒA construct of the form, É, is valid if and only if, ÉÓ with a list of painstakingly precise conditions telling you exactlywhen the compiler will reject your attempts (Òonly ifÉÓ) andwhen it accept them (ÒifÓ). Relying on an operational de-scription of what Òthe compilerÓ will do would be bad enough;relying on a warning is worse.Then, in practice, where do warnings go? They may very wellbe ignored. We have all seen cases of compilers producing hun-dreds of warnings, some meaningful and some not; after a whileprogrammers just brush them aside. When partisans of languagesthat permit potentially dangerous conversions (casts), such as Cand C++, argue with users of strongly typed languages, they pointout that really bad type errors will be caught by compiler warn-ings or-like tools; but it is easy to show by example that suchtools produce such an ocean of unjustified warnings that the fewimportant ones lost in their midst are easy to miss.This convention, Òsaying nothing means plus a warning,Óseems to be an effort at addressing a minor potential problem bycausing major potential damage. How real is the minor problemanyway? If one of your classes inherits from and you get a newversion of , it would be very foolish to accept the new versionblindly; you should check that it does not affect the assumptionsthat your class made about its parents. In Eiffel, the subcontractingrules help you in this process, by guaranteeing that the descen-dantÕs semantics is compatible with the originalÕs: the class in-variant is inherited, and in the case of overriding a feature, itsproperties must remain compatible (precondition kept or weak-most feature names suggest a specific intent, so a name clashto see whether it shouldnÕt be an overriding after all. If you havea feature called in both the parent and the heir, theyprobably have related semantics. Language conventions such asnatures differ by as little as one argument type, and ÒversionmanagementÓ techniques which legitimizes dubious cases byinterpreting them as ÒÓ declarations, are dangerous. For thedebatable sake of short-term convenience, they open the wayThe mention of polymorphism and dynamic binding helps ex-plain where the fundamental contradiction lies. The form of over-loading discussed so far may be called overloading; itgives the same name to different operations. There is no goodreason to do this. With OT, we can give the same name to dif-ferent variants of the same operation. For example, class could be part of a hierarchy of graphical classes that all have avariant of the proceduremove_horizontally h: REAL-- Displace figure by horizontal offset of -- For all points p in figure, p.x Then a call of the formwill trigger a different procedure depending on the exact type ofthe object to which happens to be attached at the timeof execution of the call. These procedures are all different, andyet they are all implementations of the same basic contract: moveall the points of a figure horizontally by . This may be called overloading and provides some of the principal expres-sive power of OO development, allowing various components ofa system to know as little as possible about each other, and hencesupporting flexible, extendible software architectures.Syntactic overloading gives the same name todifferent oper-In contrast, semantic overloadingÑto continue using thisterm for a while, although of course Òpolymorphism and dynamicbindingÓ is more preciseÑguarantees that features from a singleseed, appearing in descendants of a common ancestor, are alter-native implementations of the same underlying abstract oper-, such as Òmove horizontally by a given displacement.Ó Thisproperty is not just hand waving: in Eiffel, it is guaranteed by theinheritance rules of Design by Contract, since you can specify aprecondition and postcondition at the highest level, defining thecommon semantics, which the language rules automatically en-force on all the alternative variants. Here, OT brings one of itsmajor contributions to both programming techniques and soft-ware architecture. E I F F E L www.joopmag.comOctober/November 2001Journal of Object-Oriented Programming6 matical model for classes is simple: we consider a class as es-C: Namewhere ABdenotes the set of finite functions from to . Youmay view a finite function as simply a set of pairs, such as{[0, 0], [1, 1], [2, 4], [3, 9], [4, 16]}(part of the ÒsquareÓ function on integers); itÕs finiteÑthat isall we deal with using computersÑmeaning it only has a fi-nite set of pairs, and it is a function, meaning that no two pairsstart with the same element. For example, {[0, 0], [0, 1], [2,4]} is not a function because two of its pairs start with the sameelement 0.Our example class gives the functionnÒxÓ, horizontal_coordinate_featurereÒyÓ, vertical_coordinate_featureureÒmoveÓ, move_featurewhere ÒÓ is a string (a feature name), the associated feature, and so on.One of the nice things about such a modelÑbased on semanticwork done originally by Luca Cardelli in the 1980ÕsÑis that itimmediately generalizes to objects. The instances of class are, in this model, functions inName where the only names to be considered here are those of attributes,such as and in our exampleÑa subset of the feature namesfor the classÑand Value describes the set of possible field values.For example an object of type representing the point ofcoordinates = 0 and = 1 is, formally, the functiononÒxÓ, 0], [ÒÓ, 1]}matically applies the No-Overloading Principle without furtherado. Any form of syntactic overloading would lead to great math-Inheritance also fits nicely in this framework. Since we viewclasses as functions, a special case of sets, the basic idea for mod-eling inheritance is that a class is the ÒunionÓ of its own defini-tion and those of its parent or parents. For example, if from defined as {[ÒÓ, ], {[Ò]}, and itself in-troduces with name , then it formally is {[ÒÓ, {[ÒyÓ, ], [Ò, feature3]}. But when there is a name clashthis does not work any more, as the union of two functions is notalways a function: with= {[0, 1], [1, 2]}= {[0, 0], [1, 1]}both and are functions, but their union {[0, 1], [1, 2], [0, 0],[1, 1]} is not since it has two pairs (the first and the third) start-ing with 0 and giving conflicting values. For functions repre-senting classes, this is the case of a name clash, for example betweeninherited and new features. To make a form of union work between functions, and alwaysyield a function, we may use an Òoverriding unionÓ operator thatin the case of a conflict always selects the value from the secondoperand. (This is arbitrary; we could have chosen the first operandinstead. Either way, we have to be consistent.) A possible symbolfor this operator is, leaning toward the ÒdominantÓ operand,in the same way that the bottom bar of the Russian Orthodoxcross leans toward the thief who repented. With this operator,the result is always a function; for example:{[0, 1], [1, 2]} {[0, 0], [1, 1]} = {[1, 2], [0, 0], [1, 1]}with the pair [0,0] from the second operand overriding the pair[0, 1] from the first operand. If a class inherits from a class the resulting function will be AB, accounting for any featureredefinition in , which overrides the original from In the case of multiple inheritance, it would be a mistake touse overriding union to favor one parent over the other; this wouldmean that the order in which a class lists its parents has seman-tic consequences, certainly something we donÕt want. Instead weresort to the other technique for performing the union of twofunctions and guaranteeing that the result is still a function: mak-ing sure that their domains are disjoint, in other words that notwo pairs have the same first elementÑno two features have thesame name. Renaming achieves this by yielding a set of final namesthat satisfies the No-Overloading Principle. Then we use over-riding union with the features of the new class to take into ac-count any necessary feature redefinitions.This is only the start of a proper formal semantics for classes,objects, and inheritance, but seems to indicate that by sticking tothe No-Overloading Principle we can in the end obtain a cleanand understandable mathematical model.Mathematical model or not, this discussion will, I hope, have con-vinced you that overloading does not go well with OT, and thatkeeping things simple, in particular the correspondence betweennames and features, is the key to building a solid basis for the pow-erful techniques of OO analysis, design, and programming. 1. Meyer, Bertrand. Eiffel: The Language, Prentice Hall, Englewood Cliffs, NY., 7Journal of Object-Oriented ProgrammingOctober/November 2001www.joopmag.com