Path: utzoo!attcan!uunet!world!decwrl!shelby!neon!craig From: craig@Neon.Stanford.EDU (Craig D. Chambers) Newsgroups: comp.object,comp.eiffel Subject: Re: Do we really need types in OOPL's? Message-ID: <1990Oct6.001843.5615@Neon.Stanford.EDU> Date: 6 Oct 90 00:18:43 GMT References: <1990Oct5.010703.16019@Neon.Stanford.EDU> <1990Oct5.212947.19003@ncs.dnd.ca> Followup-To: comp.object Organization: Stanford University Lines: 85 In article <1990Oct5.212947.19003@ncs.dnd.ca> dal@ncs.dnd.ca (Andyne) writes: >The problem is that "making guarantees about type safety efficiently at >compile time" requires the use of the anti-monotinicity or >contra-variant rule (used in Trellis/Owl, Emerald, Duo-Talk, and many >other languages for checking `conformance') which DOES overly >constrain the kinds of programs people can write (even the most intuitive >subtype relationships do not hold). The other alternative is to claim >that "PRACTICAL SOFTWARE ENGINEERING does not require the contravariant >rule 95% of the time (even though novices might easily come up toy >examples where type failures occur without it), the flexibility offered by > the covariant rule >in defining subtype relations is worth more than the inability of >guaranteeing type safety for 5% of the cases at compile time", and create >kludgy checks to handle the 5% case in an unsatisfactory manner. > >Diptendu Dutta I've heard this argument before, particularly from Bertrand Meyer, and I still disagree. I think it is possible to have type safety (e.g. the contravariant rule) without overly constraining programs. The "problem" with the contravariant rule typically arises with binary-type methods in which the argument should be the same type as the receiver, and with parameterized collections in which a collection of S should be assignable to a variable of type collection of T if S is a subtype of T (this violates contravariance since the argument to the store function is a more specific type (S) in the subtype than in the supertype). To support the first case, I've been working on adding static type checking to a language with multiple dispatching. Multiple dispatching handles binary messages much better than single dispatching, since double dispatching is a pain both for the programmer and for the type system. Thus the type system would allow a subtype to specify "covariant" methods, as long as the method dispatched on both arguments. It is still type safe, because the supertype's implementation will be invoked if either of the argument's isn't the more specific type. Many of the parameterized collection problems can be solved without resorting to multiple dispatching. I believe the main reason for the "practical software engineering" problems is that the type hierarchy isn't factored well enough. In particular, the read-only interface to collections should be factored out into a supertype of the read-write interface to collections. The read-only interfaces of the two collections described above would presumably be related as desired (read-only-collection of S is a subtype of read-only-collection of T, if S is a subtype of T), since none of the functions of read-only-collections take S/T as arguments. Each read-write interface is certainly a subtype of the corresponding read-only interface, but two read-write interfaces are not subtypes, as the contravariant rule dictates. Since I contend that the primary reason for assigning a collection-of-S to a variable of type collection-of-T is to use the collection-of-T in a read-only way (e.g. iterate through it), what the programmer should have done is to declare the variable as a read-only-collection-of-T. Then the assignment is legal (since read-write-collection-of-S is a subtype of read-only-collection-of-T) *and* type safe. Other kinds of problems with collections are probably an instance of the above binary problem, and amenable to multiple dispatching solutions. Does anyone have other common examples where these two approaches wouldn't provide a clean solution? Has anyone worked on static type checking in the presence of multiple dispatching? Seeking related work.... Speaking of Bertrand Meyer and Eiffel, I believe his proposed fix to the Eiffel type rules (as reposted to comp.eiffel about a month ago) to preserve type safety in the presence of covariant type rules amounts to changing the type checking to use contravariant rules. As I read it, he's proposing to allow covariant rules (and redeclaring an inherited public method as private) as long as either there are no assignments from the subtype to variables of the supertype, or there are no uses of the covariant/redeclared functions in the supertype. But if there are no assignments from the subtype to the supertype, then there's no need for them to be related in the type hierarchy (this means that Eiffel would have to support inheritance of code w/o being a subtype, like private base classes in C++). And if there are assignments, then checking for uses simply means to ignore code that's not used in a system, and then applying contravariant rules. So covariant programs that are really used in a covariant way won't pass the proposed type checking rules, the same as if normal contravariant rules were applied from the beginning. So there goes the "support" for practical software engineering. -- Craig Chambers