Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!zaphod.mps.ohio-state.edu!wuarchive!uunet!mcsun!ukc!pyrltd!tetrauk!rick From: rick@tetrauk.UUCP (Rick Jones) Newsgroups: comp.lang.eiffel Subject: Re: Simple Eiffel Feature Call Question Message-ID: <1160@tetrauk.UUCP> Date: 8 May 91 13:22:05 GMT References: <5583@goanna.cs.rmit.oz.au> Reply-To: rick@tetrauk.UUCP (Rick Jones) Organization: Tetra Ltd., Maidenhead, UK Lines: 84 In article <5583@goanna.cs.rmit.oz.au> ajk@wren.cs.rmit.OZ.AU (Alan Kent) writes: >This may be a naive question, but I dont have a compiler installed here >at the moment to experiment with. I am having a little trouble working out >how to handle each of the following three cases in Eiffel. > >Consider three classes A, B and C where (the syntax might not be quite right) > class A export f ... > class B export f inherit A redefine f ... > class C export f inherit B redefine f ... > >Assume Current is an instance of class C. In feature f of class B I would >like to be able to... >(1) Call version C of method f (the definition in the class of the object) >(2) Call version B of method f (the definition in the current class) >(3) Call version A of method f (the parent's definition) > >As I understand Eiffel, it will always do approach (1). Correct in the normal case, although I think your terminology is a little confused. Approach (3) is quite easy - so I'll answer that first. This requires one of the less obvious combinations of renaming and redefinition. In class B you must declare: class B inherit A rename f as a_f redefine f The redefinition of f works the same is if the rename were not there, but the rename means that the parent feature is also available under its new name. (this is one of the aspects which is going to be considerably tidied up under version 3 - it's caused much confusion for many people) Thus the new definition of f will be something like: f is do a_f ; -- additional local code end Now the more difficult bit :-) Your problem statement seems to confuse the type of a variable with the type of an object. Take for example: var_b: B ; -- variable of type B var_c: C ; -- variable of type C var_b.Create ; var_c.Create ; -- create objects of the two types (1) var_b.f ; -- applies feature f of class B to object of type B (2) var_c.f ; -- applies feature f of class C to object of type C var_b := var_c ; -- assigns object of type C to variable of type B (3) var_b.f ; -- applies feature f of class B to object of type C In statements (1) & (2), the class of the variable and the object are the same, so the result is clear: in (1) the feature f as coded in class B is called, in (2) the one coded in class C is called. In (3) however, dynamic binding has to be considered. Although the variable is declared of class B, the actual object is type C. The actual feature called is the one which C inherits as f, and redefines. In other words, the code for feature f in class B is never invoked. It is a basic property of Eiffel that a class cannot prevent a descendant from redefining any of its features. This includes non-exported as well as exported ones. There is a presumption that inheritance is used responsibly, and assertions (especially the class invariant, which cannot be overridden, only added to) can trap any gross violations which a descendant may try to perpetrate. One approach to recursion or iteration where the algorithm is always the same, but the actual operation on each loop may need to be different in descendants, is to have the recursion feature call a local routine on each loop. This routine would probably not be exported and can be empty, or even deferred, in the class which defines the recursion. Descendants then only need to define (or redefine) this routine, and it will only be required to deal with one instance on each call. -- Rick Jones, Tetra Ltd. Maidenhead, Berks, UK rick@tetrauk.uucp Any fool can provide a solution - the problem is to understand the problem