mmartin@isis.UUCP (Mike Martin) (03/01/89)
I am having difficulty understanding Figure 11.1, p. 260, in the second printing of Meyer's book. It seems to me that there is an inconsistency between row 4 and row 6 in the column headed a1.f (where the dynamic type of a1 is B). In particular I can make sense of the table if the a1.f entry in row 6 were phi' instead of phi''. Is this a typo, an implementation fact of the system which isn't supposed to be consistent, or am I simply missing the point? My conceptual model of dynamic binding leads me to expect that a1.f and b1.f should agree when the latter is "legal". I don't have an eiffel system to test the table entries. I realize that there may rarely (never?) be any reason to use row 6 but I appreciate any clarification. As this may be a rather esoteric question and/or my obvious misconception, please respond by e-mail to mmartin@ducair.bitnet and I will post interesting responses. Mike Martin
kain@cognos.uucp (Kai Ng) (03/04/89)
In article <2431@isis.UUCP> mmartin@isis.UUCP (Mike Martin) writes: >I am having difficulty understanding Figure 11.1, p. 260, in the second >printing of Meyer's book. Me too. It took me quite a while to comprehend that table. My understanding of it is mostly gained from experience in using Eiffel. >It seems to me that there is an inconsistency between row 4 and row 6 >in the column headed a1.f (where the dynamic type of a1 is B). In >particular I can make sense of the table if the a1.f entry in row 6 were >phi' instead of phi''. Please see below. N.B. In case somebody don't know, if you have an early version of the book, the header of the table which reads cl.f, dl.f dl.f' should be corrected to al.f, bl.f & bl.f' respectively. >Is this a typo, an implementation fact of the system which isn't >supposed to be consistent, or am I simply missing the point? My >conceptual model of dynamic binding leads me to expect that a1.f and b1.f >should agree when the latter is "legal". I don't have an eiffel system >to test the table entries. As far as I know, that table is still correct to me. Almost all combinations have been used in our own implementation of Eiffel Object Library. >I realize that there may rarely (never?) be any reason to use row 6 >but I appreciate any clarification. This is just a start. When multiple inheritance comes into place, life is a lot more complicated. (Features of same name from different parents, same feature from different parents with different implementations orignated from the same grandparent, etc.) I've found rename and redefine in multiple inheritance is not described clear enough in the book. >As this may be a rather esoteric question and/or my obvious >misconception, please respond by e-mail to mmartin@ducair.bitnet and I >will post interesting responses. I find my way of memorizing the effect of renaming and redefining is easy, better than intepreting that table everytime, and probably is useful to many people, hence I go ahead and post it. ------------------------------------------------------------------------------- The original table on p.260 of Object-oriented Software Construction by Dr. Meyer. a.f b.f b.f' 1. f not redefined Q Q illegal f not renamed 2. f not redefined Q illegal Q f renamed f' 3. f redefined Q' Q' Q' illegal f not renamed 4. f redefined Q' Q' Q' Q f renamed f' 5. f not redefined Q'' illegal Q'' f renamed f' f' redefined Q'' 6. f redefined Q' Q'' Q' Q'' f renamed f' f' redefined Q'' ------------------------------------------------------------------------------- The Game: There is a class B which is a subclass of A; there is an instance b of type B and b is also referenced by a of type A. That is, the dynamic type of a is indeed B. We have to determine which version of a feature f is actually used if f is renamed and redefined in the subclass. Notation: [f/Q] - feature of name f and implementation Q. Rules: 1. Construct a table starting with [f/Q]. 2. In case of renaming (f to f'), place [f'/Q] to the right of the [f/Q] being renamed. 3. In case of redefining (Q to Q'), place [f/Q'] in the bottom of the [f/Q] being redefine; if there is an entry to the left place it one more line down, etc. 4. After all the renaming and redefining is done, the feature accessible by the superclass instance 'a' is always the bottommost one and the left one has precedence (and always of name f). The feature accessible by the subclass instance 'b' are all the ones reachable from the right. In case there are more than 1 in the same column, the bottom one has precedence. Case 1 (as in the table): [f/Q] <-- b.f ^ | a.f Case 2: [f/Q] [f'/Q] <-- b.f' ^ | a.f Case 3: [f/Q] [f/Q'] <-- b.f ^ | a.f Case 4: [f/Q] [f'/Q] <-- b.f' [f/Q'] <-- b.f ^ | a.f Case 5: [f/Q] [f'/Q] [f'/Q''] <-- b.f' ^ | a.f Case 6: [f/Q] [f'/Q] [f/Q'] <-- b.f ['f/Q''] <-- b.f' ^ | a.f Hope all these help. Happy OOP -- Kai Ng P.O. Box 9707 UUCP: uunet!mitel!sce!cognos!kain Cognos Incorporated 3755 Riverside Dr. (613) 738-1440 Ottawa, Ontario, ext. 6114 CANADA K1G 3Z4
genly@mfci.UUCP (Chris Hind Genly) (03/07/89)
In article <5434@corona.UUCP> kain@cognos.UUCP (Kai Ng) writes: >In article <2431@isis.UUCP> mmartin@isis.UUCP (Mike Martin) writes: >>I am having difficulty understanding Figure 11.1, p. 260, in the second >>printing of Meyer's book. > > Me too. It took me quite a while to comprehend that table. > My understanding of it is mostly gained from experience in using Eiffel. > >>It seems to me that there is an inconsistency between row 4 and row 6 >>in the column headed a1.f (where the dynamic type of a1 is B). In >>particular I can make sense of the table if the a1.f entry in row 6 were >>phi' instead of phi''. > I too had trouble with this table. I also believe it to be inconsistant. However I have the suspicion it is correct. Here are the principles I expected to be used to build the table: 1) class B inherit A rename f as f'; ... end Implies f:A and f':B invoke the same feature. Where f:A means feature name f in A. In additon if no definition is supplied for f' in B, then f:A will be used. Unless explicitly defined there will be no f:B. I imagine the absence of the rename is the same as "rename f as f". Where the first f is talking about A, and the second f is talking about B. 2) Redefined appears to be straightforward. Whatever definition is given in B for a feature name is the one invoked by that name. This first principle above is at odds with row 4 of the table in the book. This is what I expect row 4 to be. 4. f redifined Q' Q Q' Q f renamed f' The following quote from the book leads me to believe this unexpected row definition was intentional. Case 4 is like case 3; but here the original implementation Q, defined in A, is still needed in b. This often occurs because the algorithm for Q' internally calls the algorithm for Q. Without renaming, there would be no way to refer to Q within B, as the name f now denotes Q'. Renaming makes it possible to keep the old version available under a different name. But it seems like a wart to me. I would have preferred another mechanism to get at Q. Perhaps something like. class B inherit A reinherit f as f' Which would cause the feature named f' in B to be inherited from f in A. But it says nothing about what a.f invokes.
kain@cognos.uucp (Kai Ng) (03/10/89)
In article <694@m3.mfci.UUCP> genly@mfci.UUCP (Chris Hind Genly) writes: > >This first principle above is at odds with row 4 of the table in the book. >This is what I expect row 4 to be. > >4. f redifined Q' Q Q' Q > f renamed f' > >The following quote from the book leads me to believe this unexpected >row definition was intentional. > > Case 4 is like case 3; but here the original implementation Q, > defined in A, is still needed in b. This often occurs because the > algorithm for Q' internally calls the algorithm for Q. Without > renaming, there would be no way to refer to Q within B, as the name > f now denotes Q'. Renaming makes it possible to keep the old > version available under a different name. > Yes, it is intentional but I don't feel it is unexpected because that is what dynamic binding is all about. Indeed it is quite clear from the following quote from the book (p.260). For redefinition: "Can I have a different implementation for f when it is applied to entities of dynamic type B ?" For renaming: "Can I change the name under which the original (A) implementation of f may be applied to entities of static type B ?" In other words, if B inherits a feature f from A, redefining f in B with implementation Q' makes sure Q' is used when f is invoked and the dynamic type is of B; renaming f, of implementation Q, in B to f' preserves the availability of Q to B known as f' unless f' is further redefined (as in row 5 and 6). Hence row 4, no more and no less, is expected as f redefined Q' Q' Q' Q f renamed f' Furthermore, I like to point out the order of the RENAME and REDEFINE clauses is not important if there is only one of each. (I am not 100% positive if you have more than one of each). Talking about dynamic binding, I've found in some cases the binding mechanism in Eiffel is NOT that dynamic. Consider the following example comprises 4 classes: ------------------------------------------------------------------------ CLASS A FEATURE classNumber: Integer IS 1; printClassNumber IS EXTERNAL printf LANGUAGE "C"; DO printf ("%d", classNumber); END; -- printClassNumber END -- Class A ------------------------------------------------------------------------- CLASS B INHERIT A REDEFINE classNumber FEATURE classNumber: Integer IS 2; END -- Class B ------------------------------------------------------------------------- CLASS C INHERIT A REDEFINE classNumber ... classNumber: Integer IS 3 ... ------------------------------------------------------------------------- CLASS D EXPORT printB, printC INHERIT B RENAME printClassNumber AS printB; C RENAME printClassNumber AS printC FEATURE END -- Class D ------------------------------------------------------------------------- However, both d.printB and d.printC will print out the number 3 instead of 2 and 3 respectively as expected. Maybe I miss a point in terms of dynamic binding. (Dr. Meyer ?) -- Kai Ng P.O. Box 9707 UUCP: uunet!mitel!sce!cognos!kain Cognos Incorporated 3755 Riverside Dr. (613) 738-1440 Ottawa, Ontario, ext. 6114 CANADA K1G 3Z4
kain@cognos.uucp (Kai Ng) (03/11/89)
Sorry folks. The problem is my hands can type faster than my mind can think. The example provided in my previous article will not compiled if just entered as is. Thanks to Alan Myrvold (sp ?), my co-worker, who pointed that out to me. But I did code something correctly and got the result before I opened my mouth :-( In article <5506@corona.UUCP> kain@cognos.UUCP (Kai Ng) writes: > >CLASS B > >INHERIT > A REDEFINE classNumber > >FEATURE > > classNumber: Integer IS 2; > >END -- Class B >------------------------------------------------------------------------- >CLASS C > >INHERIT > A REDEFINE classNumber > > ... > classNumber: Integer IS 3 > ... >------------------------------------------------------------------------- You would get the following error message: "b", 6: Constant feature may not be redefined: classnumber *** es: error in pass2 Anyway the following is the correct example classes: -------------------------------------------------------------------------- CLASS A FEATURE classNumber: Integer IS DO Result := 1; END; -- classNumber print IS EXTERNAL printf LANGUAGE "C"; DO printf ("%d", classNumber); END; -- print END -- Class A -------------------------------------------------------------------------- CLASS B INHERIT A REDEFINE classNumber FEATURE classNumber: Integer IS DO Result := 2; END; -- classNumber END -- Class B -------------------------------------------------------------------------- CLASS C INHERIT A REDEFINE classNumber FEATURE classNumber: Integer IS DO Result := 3; END; -- classNumber END -- Class C -------------------------------------------------------------------------- CLASS D INHERIT B RENAME print AS printB, classNumber AS classB; C RENAME print AS printC, classNumber AS classC FEATURE Create IS EXTERNAL printf LANGUAGE "C"; DO printf ("\n printB prints "); printB; printf ("\n printC prints "); printC; END; -- Create END -- Class D -------------------------------------------------------------------------- Class D should be compiled as the rootClass and the following output should be expected: printB prints 3 printC prints 3 -------------------------------------------------------------------------- -- Kai Ng P.O. Box 9707 UUCP: uunet!mitel!sce!cognos!kain Cognos Incorporated 3755 Riverside Dr. (613) 738-1440 Ottawa, Ontario, ext. 6114 CANADA K1G 3Z4