[comp.lang.eiffel] redefinition and renaming

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