wtwolfe@hubcap.clemson.edu (Bill Wolfe) (11/16/89)
[This is taken from Object-Oriented Development, edited by Dennis Tsichritais, Centre Universitaire d' Informatique, Universite' de Geneve, a non-copyrighted summarization of research activity; the specific paper is "Concurrency Issues in Object-Oriented Programming, by M. Papathomas, page 207. It describes ideas which are relevant to the current Ada 9X language revision process.] Although the integration of object-oriented and concurrent programming is promising for the development of software for such applications, the design of programming languages that keep up with this promise is a difficult task. The concurrent features of a language may interfere with its object-oriented features making them hard to integrate in a single language or cause many of their benefits to be lost. For instance, encapsulation in sequential object-oriented programming languages protects the internal state of objects from arbitrary manipulation and ensures its consistency. If concurrent execution is introduced in a language independently of objects it will compromise encapsulation, since concurrent execution of the operations of objects may violate the consistency of their internal state... ...consider the interference that occurs between class inheritance and encapsulation when subclasses are allowed to access freely the instance variables of the parent class [Sny86]. In this case we may say that support for inheritance diminishes the degree of encapsulation that was achieved without inheritance... ...we identify two categories of COOPLs [Concurrent Object-Oriented Programming Languages]. We will call _orthogonal_ the category of languages where objects are unrelated to concurrency, and _non-orthogonal_ the category of languages where objects have some predefined properties concerning concurrency... According to whether or not a language supports objects of different kinds, we will further subdivide the category of non-orthogonal languages into the _non-uniform_ and _uniform_ categories. Languages in the uniform category support only one kind of object whereas language in the non-uniform category split the object world into two kinds of objects: those that serialize the execution of their operations and those that do not. Concurrent execution may be expressed by explicitly creating new threads of control, independently of objects, that communicate and synchronize by invoking the operations of shared objects. Another approach is to consider objects as active entities and express concurrent execution and synchronization by the creation of objects and their interaction. We use these two approaches to subdivide the uniform category into the categories _integrated_ and _non-integrated_. For languages in the integrated category concurrent execution is expressed by interaction of objects whereas in the non-integrated category another concept like a process or activity is used for expressing concurrent execution... The non-orthogonal class has the advantage of preventing the problems that could occur by using "unprotected" objects in [a] concurrent environment. Objects of sequential nature may be implemented in much the same way as in sequential languages. The mutually exclusive execution of the object's operations is handled automatically by the language. The distinction between different kinds of objects characterizing the non-uniform category presents some disadvantages compared to the uniform one. The programmer has to decide in advance if a certain object should be of the "protected" or "unprotected" type. Type hierarchies... are typically kept disjoint... introducing a certain redundancy in the class hierarchy... The integrated approach has the advantage that concurrent applications are structured in terms of objects which are the units of concurrent execution. The communication and synchronization of objects is expressed at the object interface which is clearly defined... Support for mechanisms similar to data abstraction in COOPLs is even more badly needed than in sequential languages but also is hard to provide. Ideally the data abstraction mechanism provided by COOPLs should separate the aspects of concurrent execution relevant to an object's implementation from the concurrent behavior of the abstraction... For reaching such goals we would need a way for describing the externally observable behavior of objects, be able to and automatically check that the realization of objects satisfies the specifications. This goal seem[s] unreachable in the near future. It would be more reasonable to provide compromises by designing abstraction mechanisms that capture more information about the behavior of active objects than abstract data types. A parallel to this approach may be drawn with the way ADTs are used in sequential programming languages and the use of assertions instead of supporting algebraic specifications and automatic verification of programs... Concurrency is not orthogonal to other aspects of object-oriented programming. Although several object-oriented languages that provide support for concurrent programming have been designed and implemented their concurrent features interfere with their object-oriented features. Furthermore, the approaches taken for concurrency may have a considerable impact on the structure of applications in a way that is contrary to the principles underlying object-oriented programming... Although abstraction mechanisms conveying more information than ADTs about the behavior of objects are badly needed in COOPLs, very little has been done in this direction by COOPLs. This may be explained by the fact that [there] does not seem to exist a consensus on formal models for the specification of the behavior of concurrent systems that would provide a basis for development of abstraction mechanisms that would extend the data abstraction mechanism to concurrent languages... We believe that the development of type systems for COOPLs is intimately related to the development of formal models for the specification of the time-dependent behavior of objects, and the development of abstraction mechanisms that will extend data abstraction to include more information about such behavior. Exception handling mechanisms are even more important in concurrent systems than they are in sequential ones. The failure of a process should not entail the failure of the whole systems since other processes may be able to proceed. Persistence is useful for the development of a host of applications. Providing support for persistence in a programming language frees the application programmer from the burden of explicitly managing persistence by using files. The atomicity properties of transactions are especially attractive in a system that has to deal with long lived persistent data. Although persistence on its own does not seem to interfere with concurrency features of a language it is not the same concerning transactions. The noninterference property of transactions seems contrary to the close interaction and communication of processes that characterizes concurrent programming and the independence of objects promoted by object-oriented programming. The full integration of concurrency with all the other aspects of object-oriented programming presents several problems that deserve more attention... further work is required for gaining more insight in the nature of these problems and for developing languages that provide satisfactory solutions.
tma@osc.COM (Tim Atkins) (11/21/89)
In article <7062@hubcap.clemson.edu> wtwolfe@hubcap.clemson.edu (Bill Wolfe) writes: > ...consider the interference that occurs between class inheritance > and encapsulation when subclasses are allowed to access freely the > instance variables of the parent class [Sny86]. In this case we may > say that support for inheritance diminishes the degree of encapsulation > that was achieved without inheritance... I have heard this before and, frankly, I don't get it. The subclass has inherited data structure definition from the parent class. Therefore its instances will contain instances of the parent data structure. This is totally local to the object! Only the definition was inherited. Why is this a bad thing? Why does it break encapsulation? I understood the encapsulation wrt data provided by OO techniques to simply state that instance data should not be accessed directly but only through a method defined on the class. Therefore, inheritance does not seem to break encapsulation. I would appreciate it if someone could set me straight here. - Tim
uucibg@swbatl.UUCP (3929) (11/23/89)
In article <1667@osc.COM> tma@osc.UUCP (Tim Atkins) writes: >I have heard this before and, frankly, I don't get it. The subclass >has inherited data structure definition from the parent class. Therefore >its instances will contain instances of the parent data structure. This >is totally local to the object! Only the definition was inherited. Why >is this a bad thing? Why does it break encapsulation? I understood the >encapsulation wrt data provided by OO techniques to simply state that instance >data should not be accessed directly but only through a method defined on >the class. Therefore, inheritance does not seem to break encapsulation. > >I would appreciate it if someone could set me straight here. As I understand your question, here is (one of) the rub(s): Class A inherits from class X. In many OO programming languages if not most that means that A gets to access X's local data items. Thus, if X had a data item 'foo', code from class A could directly access 'foo'. This means that class doesn't just depend upon the interface of X but also depends upon the implementation of X. This means that if X changes, A may have to change (and anything which is a descendant of X including all of A's descendants). This tends to make those classes near the root of an inheritance heirarchy become "rigid" very quickly, since changes can "ripple" down the heirarchy. This is viewed as a bad thing since the whole point of OO is to avoid "ripples" which propagate through a software system. Note that some languages help provide solutions for this. For example, C++ has the concepts of public, protected, and private items in a class, to help in restricting access to data members. When this is combined with the ability to inline functions, you can provide interface routines for every data member that is meant to be accessable in an efficient manner and thus hide the implementation from sub-classes without taking a major performance hit. (By the way, I'm still not totally sold on C++ but this aspect is certainly nice). Thanks, -------------------------------------------------------------------------------- Brian R. Gilstrap ...!{ texbell, uunet }!swbatl!uucibg OR uucibg@swbatl.UUCP One Bell Center +---------------------------------------------------------- Rm 17-G-4 | "Winnie-the-Pooh read the two notices very carefully, St. Louis, MO 63101 | first from left to right, and afterwards, in case he had (314) 235-3929 | missed some of it, from right to left." -- A. A. Milne -------------------------------------------------------------------------------- Disclaimer: Me, speak for my company? You must be joking. I'm just speaking my mind.
zmhasan@watdragon.waterloo.edu (Ziaul Masum Hasan) (11/23/89)
In article <1667@osc.COM>, tma@osc.COM (Tim Atkins) writes: > In article <7062@hubcap.clemson.edu> wtwolfe@hubcap.clemson.edu (Bill Wolfe) writes: > > ...consider the interference that occurs between class inheritance > > and encapsulation when subclasses are allowed to access freely the > > instance variables of the parent class [Sny86]. In this case we may > > say that support for inheritance diminishes the degree of encapsulation > > that was achieved without inheritance... > > > I have heard this before and, frankly, I don't get it. The subclass > has inherited data structure definition from the parent class. Therefore > its instances will contain instances of the parent data structure. This > is totally local to the object! Only the definition was inherited. Why > is this a bad thing? Why does it break encapsulation? I understood the > encapsulation wrt data provided by OO techniques to simply state that instance > data should not be accessed directly but only through a method defined on > the class. Therefore, inheritance does not seem to break encapsulation. > > I would appreciate it if someone could set me straight here. > > - Tim Aren't you confusing runtime behavior with compilation time? Encapsulation hides representation. Accessing instance variables means you can directly use or refer to that variable in any method that you define in the subclass (S) of a class (C). In other words, the scope of this variable defined in C spans up to the subclass. Of course, this violates encapsulation (or information hiding). If the representation of the instance variable is changed in C (say, from array to linked list), all the methods in all the subclasses down the class hierarchy that used that variable directly have to be rewritten and recompiled. Had we used method to access (refer) that variable, modification in one class was sufficient. Languages vary in defining what to inherit. In smalltalk subclasses inherit both instance variables and methods. Any method can directly use any inherited instance variable. But any other class that is not a suclass of a class C, but simply uses C by creating an instance of it, can access variables of C only through methods. In some other languages a class can access instance vriables of any other class only through methods. C++ has a flexible mechanism in defining what to inherit i.e., public, private, friend constructs. Masum Hasan Ziaul Masum Hasan ------------------------------------------------------- zmhasan@watdragon.waterloo.edu ------------------------------------------ University of Waterloo, Computer Science -------------------------------- Office Automation Lab ---------------------------------------------------
anders@cui.unige.ch (BJORNERSTEDT Anders) (11/23/89)
In article <1667@osc.COM> tma@osc.UUCP (Tim Atkins) writes: >In article <7062@hubcap.clemson.edu> wtwolfe@hubcap.clemson.edu (Bill Wolfe) writes: >> ...consider the interference that occurs between class inheritance >> and encapsulation when subclasses are allowed to access freely the >> instance variables of the parent class [Sny86]. In this case we may >> say that support for inheritance diminishes the degree of encapsulation >> that was achieved without inheritance... > >I have heard this before and, frankly, I don't get it. The subclass >has inherited data structure definition from the parent class. Therefore >its instances will contain instances of the parent data structure. This >is totally local to the object! Only the definition was inherited. Why >is this a bad thing? Why does it break encapsulation? It does break encapsulation. Whether or not this is desirable is another matter. If you make the distinction between specification and implementation of classes and considder inheritance of specifications as the primary thing then you do want encapsulation. But if inheritance of implementation (including representation) is the primary thing then you dont want encapsulation. Note: You may have both inherritance of specification and inheritance of implementation at the same time, in fact this is what you get by default in nearly all existing oo-languages. The question then becomes what you want to emphasize: the inheritance of an abstract datatype or the inheritance of a concrete datatype ? The programmer implementing a supertype may not be the same person as the programmer implementing the subtype and may not want implementors of subtypes to build in dependencies on, or make assumptions about, the internal representation of the supertype (same arguments as always for encapsulation). Thus, yes the instance contains "instances" of the parent structure, and yes this is totally local to the object, but you may still want encapsulation (or partitioning) internally in the object. If inheritance of specification is the emphasis you may still have default inheritance of implementation. This just means that the implementor of the subtype is liberated of the job of providing the implementation for the supertypes. It does not mean that the implementor of the subtype can "poke arround" in the implementation of the supertype. Anders --------------------------------------------------------------------- Anders Bjornerstedt E-mail: anders@cuisun.unige.ch Centre Universitaire d'Informatique 12 rue du Lac, CH-1207 Geneva --------------------------------------------------------------------- Tel: 41 (22) 787.65.80-87 Fax: 41 (22) 735.39.05 Home: 41 (22) 735.00.03 Telex: 423 801 UNI CH ---------------------------------------------------------------------