Xref: utzoo comp.lang.eiffel:1370 comp.object:2497 Path: utzoo!censor!geac!torsqnt!lethe!yunexus!ists!helios.physics.utoronto.ca!news-server.csri.toronto.edu!cs.utexas.edu!swrinde!zaphod.mps.ohio-state.edu!pacific.mps.ohio-state.edu!linac!att!pacbell.com!ames!pasteur!agate!shelby!neon!craig From: craig@Neon.Stanford.EDU (Craig D. Chambers) Newsgroups: comp.lang.eiffel,comp.object Subject: Re: Inheritance and Information Hiding Message-ID: <1991Feb3.225619.29491@Neon.Stanford.EDU> Date: 3 Feb 91 22:56:19 GMT References: <488@eiffel.UUCP> <1991Feb1.015749.10111@Neon.Stanford.EDU> <1081@tetrauk.UUCP> Organization: Stanford University Lines: 79 In article <1081@tetrauk.UUCP> rick@tetrauk.UUCP (Rick Jones) writes: >Has anyone tried to address this problem by considering that a class >essentially has two interfaces? One - the "read" interface - provides >information about the object in its current (abstract) state. The other - the >"write" interface - offers facilities to change the object. It seems that if >the language supported the ability to define not only the class TYPE of a >variable, but also the class USAGE (read or write), then the restrictions would >be clearer, both to the compiler and to the programmer. It's a little like the >C++ "const" qualifier, but taking the semantic implications a lot further. I've noticed the same read-only v. read-write interface problem. It frequently arises in parameterized data types like collections, in which the read-only interfaces to two differently instantiated collections are subtype-related in the same way that the instantiating types are related (read-only-collection[S] <= read-only-collection[T] iff S <= T, where "<=" means "is a subtype of"), the two write-only interfaces are related in the opposite way, and consequently the two read-write interfaces are unrelated. I described this situation in a posting to comp.object a while back. I've been working on a new o-o language design and have been thinking about ways to allow the programmer to specify "sub-interface" indications for each member, much in the same way that public v. private subinterfaces are distinguished in many languages. Then uses of the type (e.g. type declarations) could also specify a subinterface, such as the "read-only" subinterface of a collection. The present polygon/rectangle example could benefit from subinterfaces, since the add_vertex operation could be qualified with the "resizable" subinterface. I'm concerned a bit about achieving the desired syntactic conciseness; "read-only array" is a lot longer than "array". Maybe the compiler could somehow infer the right subinterface. Of course, subinterfaces aren't strictly required, since each subinterface could just be a separate type/class. However, subinterfaces would work well with hierarchies of e.g. collections each with similar subinterfaces, while the manual method would quickly get complicated and hard to maintain. So subinterfaces seem like a qualitative increase in expressive power. If they could be integrated with the already-present public vs. private subinterfaces, then no new language concepts would be needed (just an existing concept generalized). >Eiffel would be well suited to handle this notion, since it already >distinguishes between functions/attributes and procedures. The concept of >declaring an Eiffel reference as "read-only" would simply prevent it being used >to call procedures of the class - only access to attributes and functions would >be allowed (good Eiffel design avoids the use of functions which have side >effects on the the object's abstract state). This sounds like you're proposing a built-in read-only subinterface much like const in C++. I would like the various subinterfaces to be completely user-defined, without any notion of a read-only subinterface embedded in the language. Also, in some cases a function-only subinterface as you suggest could still have the same subtype problems; the question is whether the types of the arguments to the function are supertypes of the argument types of overridden function in the superclass (i.e. the contravariance property of function subtyping). >This is not a substitute for >Bertrand's more general global type-checking, but would make code clearer in >representing the current use of the object, and catch errors earlier. Bertrand's type-checking rules are *less general* than subinterfaces, since what his rule really accomplishes is removing features that are *never* called from the interfaces of classes (and treating inheritance links as subtype links only if assignments of the subclass to the superclass are actually made; this half of the rule doesn't come into play here). With subinterfaces, however, different parts of a class can be ignored in some cases and used in others. For example, the add_vertex feature of polygons could be in a special subinterface marked "resizable", and rectangles could be declared as a subtype of the non-resizable subinterface of polygons. Then "p1 := r" assignments and "p2.add_vertex" calls could appear in the same program, as long as p1 was declared to be the non-resizable subinterface of polygons, and p2 was declared as the resizable interface. This is not possible with Bertrand's type-checking rules. -- Craig Chambers