Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!usc!snorkelwacker.mit.edu!bloom-beacon!eru!hagbard!sunic!mcsun!ukc!tcdcs!bofin!cjmchale From: cjmchale@cs.tcd.ie (Ciaran McHale) Newsgroups: comp.object Subject: Re: Concurrency vs Inheritence Message-ID: <1991Apr8.184023.9264@cs.tcd.ie> Date: 8 Apr 91 18:40:23 GMT References: <908@antares.Concordia.CA> Organization: DSG, Dept. of Comp. Sci., Trinity College, Dublin. Lines: 140 In <908@antares.Concordia.CA> bcheung@omicron.cs.concordia.ca (CHEUNG yik-chi) writes: >I just begin working on concurrency vs inheritence. >Is there some people also working on the same thing. >If yes, may we open this issue for infomation change? and ...etc. I've already posted an article containing about 30 bib references. Any citations I give in this posting refer to the other article. In another posting, Oscar Nierstrasz (oscar@cui.unige.ch) outlined the basic problem: The essence of the problem is that (1) synchronization code embedded in superclasses is hard to reuse by subclasses that must cooperate with the inherited code, and (2) superclass code has limited reusability since it has no way of knowing what additional synchronisation policies the subclasses wish to introduce. That's basically it, and said much more concisely than I probably could have. As for approaches to solving it ... I think a good approach is to keep the functional code (i.e., code which implements the functionality of operations without regard for synchronisation concerns) separate from the synchronisation code. (BTW, this is one of Bloom's modularity requirements.) This will hopefully allow sychronisation code and functional code to be inherited/changed independantly of each other. Once you've decided to keep synchronisation code separate from functional code, the next issue to consider is "What should the synchronisation code look like?" (Warning: I am biased in answering this because this is the area of my research.) I would say that there are two basic choices: prodecural or declarative. Procedural synchronisation mechanisms ------------------------------------- Think up of a few synchronisation primitives. Add these to a language. Now you can implement synchronisation policies by combining these primitives with the language's sequential flow control and data structures. Hence synchronisation policies are implemented via algorithms, which leads me to term this class of synchronisation mechanisms "procedural" (the term "algorithmic" is a bit of a tongue-twister for me:-). Advantages: 1. Programmers know how to write algorithms. Synchronisation policies can be written in terms of an algorithm. Hence programmers can implement synchronistaion policies (in theory, anyway:-). 2. The full flexibility of the language (flow control and data structures) can be used in the implementation of synchronisation policies. Disadvantages: 1. Ada does it this way :-) 2. Synchronisation policies implemented in procedural mechanisms are often difficult to understand. 3. If a subclass wishes to slightly modify the synchronisation policy (to cater for any extra operations it might define) then it may have to totally reimplement the synchronisation policy. Declarative synchronisation mechanisms -------------------------------------- Develop some expressive notation which allows us to concisely state a wide range of synchronisation policies. Use this notation to state our desired policy, and let the compiler figure out how to implement it. Hence the term "declarative"; you simply declare what you want and `hey presto' it's done. Advantages: 1. "The specification _is_ the implementation." i.e., it's easy to implement a particular policy since all we need do is specify it. 2. Synchronisation policies expressed in a declarative manner are often much shorter and easier to understand than those implemented in a procedural mechanism. 3. Some declarative mechanisms (Eiffel 3.0 and Guide) allow a subclass to incrementally modify the synchronisation policy of its superclass, rather than modification on an all-or-nothing basis. Disadvantages: 1. Most declarative mechanisms have limited expressive power which means that they can elegantly express many simple synchronisation policies but are utterly inadequate for more complex ones. If the policy cannot be expressed directly in the declarative mechanism then the programmer will have to fallback to using the mechanism in a more procedural oriented way. The usage of "synchronisation procedures" (as Bloom calls them) in Path Expressions is a classic example of this. The solution to the "symmetric readers/writer" in the second Guide paper I referenced is also an example. 2. The declarative approach does not lend itself to utilise the flow control constructs and data structures of the language. Hence, the mechanism must be extremely expressive to overcome this limitation (and most aren't). ----------------------------------- o ----------------------------------- Procedural Vs Declarative: which approach is best? At the current state of the art, there is no one outright winner. However, my (biased) opinion is that declarative mechanisms _will_ improve over the next few years to the point where they can be used to easily solve many difficult synchronisation policies. Theorists might also prefer them since expressively powerful declarative mechanisms might more readily lend themselves to concurrent-program proving. Examples of procedural mechanisms include: Pool, Ada, Caromel, Enabled Sets, Monitors, Mediators, Hybrid, Sina. Declarative mechanisms include: Path Expressions (all variations of), synchronisation counters (DRAGOON, Guide), Synchronizing Resources, Eiffel 3.0 [In the 1990 TOOLS proceedings you can find Bertrand Meyer's brief discussion of the new synchronisation mechanism for Eiffel. Sorry, I don't have a more complete bib reference for it.] Ciaran. -- Ciaran McHale "There's a lot to be said for verbosity." ---- Department of Computer Science, Trinity College, Dublin 2, Ireland. \ / Telephone: +353-1-772941 ext 1538 FAX: +353-1-772204 \/ Telex: 93782 TCD EI email: cjmchale@cs.tcd.ie