Re: Inheritance Questions

Daniel F Moisset <[email protected]>
Newsgroups gmane.comp.lang.eiffel.smalleiffel
Organization Except
Message-ID <[email protected]>
On Thu, 2005-04-14 at 10:49 +0100, Frank Salter wrote:
> I would like to ask you to examine the following facts and consider 
> their implications.

It's a very interesting problem. For theorists, but for practical
purposes too.

> The following program compiles correctly and produces the expected output.
> (...)
> ==============================================================
> If the class STAFF_LIST attempts to "insert" rather than "inherit" the 
> LINKED_LIST, the program fails to compile with the following message:
> 
> compile test -o test
> ****** Fatal Error: Cannot pass `other' which is of type STAFF_LIST
> into formal type COLLECTION[EMPLOYEE].
> Line 190 column 20 in LINKED_LIST (/opt/SmartEiffel/lib/storage/collection/linked_list.e):
>          from_collection(other)
>                          ^     
> Line 284 column 26 in LINKED_LIST (/opt/SmartEiffel/lib/storage/collection/linked_list.e):
>    from_collection (model: COLLECTION[like item]) is
> (...)      

The culprit here is {LINKED_LIST}.copy (line 190)

    copy (other: like Current) is
        do
            from_collection(other)
        end

What you're trying to do clearly calls for non-conforming inheritance;
but this example shows that it's not working properly together with
anchors. I'm not talking about SmartEiffel (the message is perfectly
reasonable), but the mechanism itself.

LINKED_LIST conforms to COLLECTION, so "like Current" conforms to
COLLECTION too (for LINKED_LIST and any conforming descendant). But
here, when inserting LINKED_LIST, you got a new class where like Current
does not conform to COLLECTION any longer...

This will probably happen in any case where an expression with an like
Current is used in a place where a non-anchored type is requested.
This raises a lot of questions about the interaction of these two
mechanisms (non conforming inheritance (NCI) and ¿anchors?) that should
be researched... I don't think there's an easy answer.

At this time, I think the possible answers (none satisfactory) are:

a) Blame the language/compiler: "You should not be able to write (at
LINKED_LIST) code passing an anchor to a explicitly typed parameter,
because that forbids NCI. Bad language that allows it/Bad compiler that
does not check it". This could be enforced at a language level, but
being very restrictive (very legitimate uses, like from_collection,
would be forbidden).

b) Blame the library writer: "Library writers shouldn't write methods
like that, breaking possible reuse". The whole SE/ISE/whatever library
could be fixed to avoid this. But that doesn't mean it won't happen
again, in developer classes. It's hard to say if the assumption that all
classes getting the copy method from COLLECTIONS will be COLLECTIONs
(i.e., what breaks here) is too strong or not to drop it.

c) Blame the mechanism: "OK, NCI is broken, I'll just use inherit". In
fact that was the proposed way of doing it before NCI. It's a
possibility, but it's sad to drop an apparently nice and useful feature.

d) Blame the developer: "When doing tricks like inheriting standard
classes, things break. It's my job to fix them". That's quite true,
essentially of classes redefining standard methods (like copy, is_equal)
which are used everywhere. And some times you have to do some
inheritance juggling (renaming, redefining, undefining, joining) to get
it right. Perhaps you can do just that (redefining copy inside
STAFF_LIST).

Trying that I found another problem:

    get_new_iterator: ITERATOR[E] is
        do
            create {ITERATOR_ON_LINKED_LIST[E]} Result.make(Current)
        end

note that no anchors are used here, but the problem repeats. So the
problem is not the use of anchors, but the use of Current. Which makes
sense: After inserting LINKED_LIST, Current may be now something almost,
but not quite, completely unlike a LINKED_LIST.


> ==============================================================
> 
> Now if the following export clause is applied to the inherited 
> LINKED_LIST then the compiler produces 69 messages. This
> output is elided as all the messages are similar and originate in the 
> library classes.
> 
> export {COLLECTION, GENERAL, LINKED_LIST, NONE} all;
> 
>                     {LINKED_LIST, TEST}  make, add_last, do_all
>             end
> (...)
> ==============================================================

I've crossed this problem before. Specially when porting programs from
SE1.1 (where restricted export was the way of doing this) to SE 2.1.
I think a single warning per-export clause instead of a warning
per-method should be enough; perhaps an option of disabling it (given
that it marks as faulty code that was in the suggested style up to
recent times).

> So I would like to pose the following questions particularly to the 
> theorists.
>           Does the above demonstrate a missing Eiffel inheritance 
> facility akin to "inherit" and "insert"?

*Another* feature will just add more incompatibilities between language
mechanism. Look at what happened when NCI was added (The meaning of
"Current" was broken).

>           As the above seeks to impose restrictions on the inheritance, 
> would the use of a further facility
>           such as "restrict" improve the ability of a compiler to work.

What is "restrict"?

Thanks for the interesting discussion :)

	Daniel

PS: You should post about this to comp.lang.eiffel too...
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.