Xref: utzoo comp.lang.misc:7147 comp.object:2947 comp.lang.eiffel:1478 Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!zaphod.mps.ohio-state.edu!pacific.mps.ohio-state.edu!linac!att!pacbell.com!ucsd!hub.ucsb.edu!eiffel!bertrand From: bertrand@eiffel.UUCP (Bertrand Meyer) Newsgroups: comp.lang.misc,comp.object,comp.lang.eiffel Subject: Re: CHALLENGE: heterogeneous collections Message-ID: <520@eiffel.UUCP> Date: 28 Mar 91 17:32:13 GMT References: <1991Mar25.220525.11087@leland.Stanford.EDU> <1991Mar28.030354.25051@leland.Stanford.EDU> Organization: Interactive Software Engineering, Santa Barbara CA Lines: 111 From <1991Mar28.030354.25051@leland.Stanford.EDU> by hoelzle@leland.Stanford.EDU [Order of paragraphs reversed]: > Suppose you have two classes T and SubT, where SubT is a subtype of T > (in the strict sense of `subtype'). You also have the lists > > listA: List[A] > listB: List[B] > > (where List[T] is a generic List including the method insert(elem: T)) > > Also suppose that there exists a procedure someProc(l: List[A]) which > (among other things) may invoke the function a() on some elements of the > list (a() is defined in A). > > Now the problem: List[T] is not a subtype of List[SubT] because of the > insert method (contravariance). Thus, someProc(listB) is illegal even > though it is perfectly safe since all of its elements are guaranteed to > understand a(). > Yes, genericity *is* useful (and needed), but it is only a partial > solution. [The discussion below uses LIST rather than List and some_proc rather than someProc.] Here constrained genericity does provide a solution. (Not necessarily *the* solution, but the best one that I know.) The reasoning (as sketched in a previous posting) is that if some_proc is to apply function a to objects of type T, it needs some reassurance that such objects indeed have a function a. It does not need to know what the function actually does, simply that it exists, has a certain signature (argument and result types) and, if so desired, certain semantic properties expressed by a precondition and/or a postcondition. The solution, then, is to introduce a deferred (i.e. abstract) class SPECIFIC, with a deferred (not implemented) function a: deferred class SPECIFIC feature a: SOME_TYPE is deferred end; ... end -- class SPECIFIC to request that any actual generic parameter LIST be a descendant of SPECIFIC: class LIST [T -> SPECIFIC] feature ... end -- class LIST and to make sure that A includes SPECIFIC among its parents. Of course, this means that B to must be a descendant of SPECIFIC, and Mr. Hoelzle's point is probably that this is inappropriate since some_proc will only be called with arguments of type LIST [A]. However the problem does not arise in this way in ``pure'' object-oriented programming of the Simula/Eiffel (and, unless I am mistaken, Smalltalk) style. In this world some_proc would not take an argument l of list type, as in Mr. Hoelzle's statement of the problem given above, but would be a procedure in a list class. Then two possibilities arise: - Either some_proc appears in the generic class LIST as given above, in which case it is legitimate to require that B be a descendant of SPECIFIC since some_proc will be applicable to targets of type B. - Or we do want some_proc to be applicable only to targets of type A. Then we do not need constrained genericity; we should declare some_proc not in the basic LIST class but in a descendant written specifically for that purpose: class LIST_OF_A inherit LIST [A] feature some_proc is local current_list_element: A x: SOME_TYPE do from ... loop ... x := current_list_element.a --<------ end ... end -- some_proc end -- class LIST_OF_A In the call marked --<-----, the application of function `a' to `current_list_element' is typewise valid since the function is assumed to be a feature of class A. In summary, static typing means that the software text must make explicit the assumptions about what operations are applicable to what entities, and then must not go beyond these assumptions in applying operations to entities. -- -- Bertrand Meyer bertrand@eiffel.uucp