Path: utzoo!utgpu!news-server.csri.toronto.edu!mailrus!cs.utexas.edu!swrinde!ucsd!hub.ucsb.edu!eiffel!bertrand From: bertrand@eiffel.UUCP (Bertrand Meyer) Newsgroups: comp.object Subject: Re: inheritance and `type loss' Message-ID: <366@eiffel.UUCP> Date: 13 Jul 90 17:04:52 GMT References: <1130012@gore.com> <683@bacchus.esa.oz> Organization: Interactive Software Engineering, Santa Barbara CA Lines: 103 Just a note on how this is understood in Eiffel, with no attempt to compare with other object-oriented languages. (Sorry, it is longer than originally anticipated, since it starts from the basic ideas.) As part of the paradigm, every operation has one or more arguments, and one of them, the ``target'' of the operation, plays a special role. This convention makes it possible to unify the concepts of module and type into a single one - the concept of class. A class is a module, packaging together a set of facilities; it is also a type, describing a set of potential run-time instances. By accepting that every operation ``applies to'' one distinguished target, we can merge the two notions by considering that the facilities packaged in the class (viewed as a module) are precisely the operations ``applying to'' individual instances of the class (viewed as a type). This is somewhat constraining, sometimes forcing us to choose ``the'' target of a multi-argument operation in apparently arbitrary ways, but serves as a powerful structuring facility and opens the road to many other properties, in particular inheritance. The convention is reflected in the standard syntax for application of operations (features): dot notation, as in /1/ document.print (my_macro_package, my_printer) where the target appears before the period, and any further arguments appear in parentheses after the operation name. Dynamic binding is also predicated on the ``single target'' assumption: if there is more than one version of an operation applicable to the target, the semantics of object-oriented computation prescribes that the choice be made on the basis of the run-time form of the object to which the target is attached. For example, if there are various types of documents, each described by a different class, and these classes provide different versions of the feature `print', then the execution of /1/ will select the appropriate version on the basis of the run-time type of `document'. Not surprisingly, the decision to base dynamic binding on the type of just one argument (the target) is subject to criticism. What if multi-criterion discrimination is desired? But this convention keeps things simple, and the few examples I have seen of mechanisms attempting to support dynamic binding on more than one argument were not convincing. Using dot notation for an arithmetic operation might give something like /2/ i.plus (j) with dynamic binding on the first argument only. The type of the result of /2/ is the type declared for the result of function `plus', as defined or redefined in the class corresponding to the dynamic type of `i'. The Eiffel notation for infix routines makes it possible to use standard syntax instead of /2/: /3/ i + j If i is declared of type C, this assumes that the declaration of the feature in C uses a name of the form `infix "+"' rather than `plus': /4/ infix "+" (other: C): C is -- Sum of current element and `other' do ... Implementation of addition ... end -- "+" This is indeed the kind of declaration found in Kernel Library classes such as INT, describing integers, FLOAT, describing floating-point reals, etc. (As readers familiar with Eiffel will know, we might in some cases prefer to declare `other' and the result as being of type `like Current' rather than C.) The ``infix'' mechanism (as the similar ``prefix'' mechanism) is, however, purely syntactical. /3/ is a mere equivalent for /2/, with the only difference that the feature was declared with name `infix "+"' rather than `plus'. In both /2/ and /3/, the choice of the version to be applied depends solely on the type of `i'. The type of `j' plays no role. As with /2/, the type of the result of /3/ is the type declared for the result of `infix "+"' in the class corresponding to the dynamic type of the object to which `i' is attached at the time of execution. If that class is a descendant of C, this result type must itself be a descendant of C. (A descendant of a class is the class itself, or a direct or indirect heir.) -- Bertrand Meyer bertrand@eiffel.com