[comp.lang.eiffel] Possible Inheritance Anomaly

dcr0@bunny.UUCP (David Robbins) (01/10/89)

I've come across an apparent anomaly in the Eiffel inheritance mechanism.
I'm not really sure if this is a bug or if it is simply that Eiffel does
not behave in the way that I would expect.  It has to do with renaming an
inherited feature, and is perhaps best illustrated by example.  So here
goes:

I have three classes named ROOT_CLASS, A, and B, defined as follows:

root_class.e --

   class ROOT_CLASS
   inherit STD_FILES
   feature
      an_a: A; a_b: B; b_invoked_as_a: A;
      Create is do
	 an_a.Create; a_b.Create; b_invoked_as_a := a_b;
	 putstring("Calling A.f1:  "); an_a.f1;
	 putstring("Calling A.f2:  "); an_a.f2;
	 putstring("Calling B.f1:  "); a_b.f1;
	 putstring("Calling B.f2:  "); a_b.f2;
	 putstring("Calling B.f3 (which is really A.f1): "); a_b.f3;
	 putstring("Calling B.f1 through A's interface:  "); b_invoked_as_a.f1;
	 putstring("Calling B.f2 through A's interface:  "); b_invoked_as_a.f2
      end
   end

a.e --

   class A export f1, f2
   inherit STD_FILES
   feature
      f1 is do putstring("I am A.f1"); new_line end;
      f2 is do putstring("I am A.f2"); new_line end
   end

b.e --

   class B export f1, f2, f3
   inherit A rename f1 as f3 redefine f2
   feature
      f1 is do putstring("I am B.f1"); new_line end;
      f2 is do putstring("I am B.f2"); new_line end
   end

Results of Execution --

   Calling A.f1:  I am A.f1
   Calling A.f2:  I am A.f2
   Calling B.f1:  I am B.f1
   Calling B.f2:  I am B.f2
   Calling B.f3 (which is really A.f1): I am A.f1
   Calling B.f1 through A's interface:  I am A.f1
   Calling B.f2 through A's interface:  I am B.f2

The apparent anomaly is what happens when B.f1 is called through A's
interface.  I would have expected that regardless of what interface is
used, a call to B.f1 would execute the feature that B has defined as
its f1.  Yet here, when B is called through A's interface, the f1
feature executed is that which A defined as f1!  I suppose that some
argument could be made that this is appropriate behavior, but it surely
is contrary to what it is done in other object-oriented languages.

I wonder what Bertrand Meyer intended the behavior to be in this case?
Is this a bug or is it by design?  Do you comp.lang.eiffel readers have
an opinion as to whether this is or is not a bug?
-- 

Dave Robbins                    GTE Laboratories Incorporated
drobbins@gte.com                40 Sylvan Rd.
...!harvard!bunny!drobbins      Waltham, MA 02254

akwright@watdragon.waterloo.edu (Andrew K. Wright) (01/10/89)

In article <6416@bunny.UUCP> dcr0@bunny.UUCP (David Robbins) writes:
>I've come across an apparent anomaly in the Eiffel inheritance mechanism.

>   class B export f1, f2, f3
>   inherit A rename f1 as f3 redefine f2
>   feature
>      f1 is do putstring("I am B.f1"); new_line end;
>      f2 is do putstring("I am B.f2"); new_line end
>   end

This seems to me to be a bug in the compiler.  However, whether your
example is also incorrect is not made entirely clear in the book.
The problem is the meaning of "rename": if you are renaming
f1 as f3, does this mean that you can now define your own f1
without a redefine clause?

In the current compiler, it appears that you cannot, but the compiler
misses generating an error message for your example.
Changing the inherit clause of class B to
>   inherit A rename f1 as f3 redefine f2, f1
fixes your example.

However, I would vote that the compiler be changed to accept your
example as valid.  Thus rename implies redefine (in a sense).

Andrew K. Wright      akwright@watmath.waterloo.edu
CS Dept., University of Waterloo, Ont., Canada.

dcr0@bunny.UUCP (Dave Robbins) (01/13/89)

In article <10691@watdragon.waterloo.edu>, akwright@watdragon.waterloo.edu
(Andrew K. Wright) writes [in response to my earlier posting]:
> 
> This seems to me to be a bug in the compiler.  However, whether your
> example is also incorrect is not made entirely clear in the book.
> The problem is the meaning of "rename": if you are renaming
> f1 as f3, does this mean that you can now define your own f1
> without a redefine clause?
> 
By everything I can get my hands on, "rename f1 as f3" means that the
name "f1" no longer is defined in the class.  Eiffel allows me to define
a new "f1" as in my example.  Further experiments show that the new
definition of "f1" can have arguments and a type entirely incompatible
with the inherited "f1" which has been renamed.  All the evidence suggests
that within the subclass, the name "f3" has taken over all the meanings
inherited from "f1" in the parent class, and left the name "f1" totally
unused.  This is what I would naturally expect "rename" to mean, and nothing
Meyer has said about the semantics of rename suggests differently.

I am more and more convinced that there is indeed a bug in the Eiffel
implementation, and not in the language or in my understanding of the
language.  I think the bug is simply that in the presence of renaming
the feature "lookup" mechanism doesn't always find the appropriate feature.
I have additional examples that illustrate this, which I may post in a few
days.

Dave Robbins                    GTE Laboratories Incorporated
drobbins@gte.com                40 Sylvan Rd.
...!harvard!bunny!drobbins      Waltham, MA 02254