Dear java-threads and occam-com, [with apologies to those on both lists] I've been thinking about (OO-)inheritance and how it relates to the active objects we have been talking about for Java. I'm worried that: o we can have passive objects and inheritance or ... o we can have active objects and `proper' object-orientation but ... we can't have both! If this is true, which would you chose? Recapping: passive objects encapsulate data and `methods'. The behaviour of the object is determined by its methods. The methods are just procedures (or functions) that are called by other objects. Implementation of those methods, therefore, has to be caller-oriented and not object-oriented. This means that the algorithmic structures within the methods do not parallel the behavioural specification of the object and that they are hard to design and prove. Whereas: active objects also encapsulate data and their managing algorithms. These algorithms are expressed through local flow(s) of control and directly reflect the behavioural specification of the object -- i.e. the algorithms are `object-oriented'. This makes for simplicity. Active objects are networked via an interfacing medium constructed from passive objects belonging to a (hopefully) small set of classes (such as channels, buffers, semaphores, events, buckets, ...). Now, objects are instances of classes and classes are related to each other by a sub-typing relation called `inheritance'. An object of a sub-type class is always a member of its super-type class. This means that if all elements of the super-type are acceptable in some context, then any elements of the sub-type will also be acceptable. In OO-languages, the sub-type class inherits all the attributes from the super-type. These attributes are the data and methods of the super-type. The sub-type can add extra data and methods (i.e. become more complex, which is somewhat counter-intuitive) and can re-implement (`override') some of the inherited methods. The sub-type cannot dispense with any inherited data fields or methods, since that would break the sub-typing relationship with the super-type. For passive objects, adding new data fields and new methods and changing existing methods is straightforward. The methods are a set of procedures that stand on their own. Their callability does not depend on the state of their objects -- they can always be called (which leads to trouble when another object calls a method and discovers that the method's object's state is not fit for the method to have been called ... life being what it is, this tends to happen quite a lot). But sub-typing inheritance on active objects is not straightforward! Consider an active object with a channel interface. The responsiveness of that object to one its channels does depend on its state. Also, the active object may choose to be responsive to a channel at many points in its life (i.e. at many points in the thread of control in its algorithm that directly -- and in an object-oriented manner -- implements its life). It doesn't make sense to talk about `overriding' the response to that channel (in the way we can `override' the implementation of a stand-alone method). Which particular response to the channel is to be overridden ... one, some or all of them? It doesn't make sense to talk about about `adding' extra channels (or whatever) to the interface: where (and in how many places) do we add the response to the extra channel? Adding a response for a new channel (or changing an existing response) has impact on the way the object responds to its other channels. The semantics of the whole object has been changed and -- ouch -- the whole implementation will have to be re-verified. In a passive object, there is no life in the object outside its method calls. So, adding an extra method need have no impact on the semantics of existing methods. Hence, the claimed benefits of reuse (of the existing methods) arising from inheritance. However, I would not take it for granted that exisiting method semantics are preserved through inheritance and would like to be reassured that this really is the case! [Note: an active object can have a restricted design so that it mimics a passive one. For example, an occam3 MODULE TYPE implemented by a SERVER, none of whose guards contain pre-conditions and none of whose guard bodies contain channel operations associated with the other channel guards. Such objects are just the same as passive ones and could be part of an inheritance tree. But that's quite a restriction and we do lose the whole power and simplicity resulting from truely active processes.] In the Java binding for active objects, the life of the object is expressed entirly within the `run' method. So far as inheritance is concerned, we either re-use the `run' method intact or replace it entirely. Its interface is *not* represented by a set of methods that can be changed one-by-one. Its interface is represented by the parameters given to its `constructor'. So, what is inheritance for? Is it to enable reuse of code through the gradual refinement of behaviour -- the adding of new features and the modification/specialisation of old ones? If the latter, there may be another way to do it than through sub-typing. For active components, we don't seem to have the choice of sub-typing ... Active components have very clean interfaces and they beg to be reused intact. Behavioural changes can be made -- incrementally -- by composing active objects together without changing any sub-components. For example, the dining philosphers' college can be attached unchanged to a variety of animation components to give us a variety of exciting behaviours -- from a scrolling teletype display through to interactive total immersion 3-D virtual reality with quadrophonic sound effects. We don't need inheritance for this; we just need the right components and the right kind of glue for composing them. Their semantics compose nicely in line with the evolving design. Reused components need no re-verification because they are reused in one piece and because their semantics are independent of the context of that reuse. Where `inheritance' (of a different kind) may be useful is for inheriting interfaces. It would be very nice to have an algebra for constructing new interfaces from old, without having to write out laboriously all the old bits we wish to reuse unchanged. It should be possible to eliminate bits of exisiting interfaces that we don't need. We need to be able to take (disjoint) unions of interfaces (being careful about name clashes), as well as intersections and subtractions. Java already has some of this with its IMPLEMENTS mechanism. Adding an INTERFACE algebra to occam (or our active Java objects) may be *much* more significant for re-use than worrying about the absence of an `inheritance' mechanism. The result is not a sub-typing relation, but so what? But, what do others think ... ? Cheers, Peter.