A modeling perspective

Perhaps the most dominant metaphor in object-oriented design is what we have called the client/server model in sections theme and contracts. This model is supported by the notion of contracts as initially introduced for the language Eiffel. Not accidentally, the client/server model is also an important paradigm in distributed programming, and hence may serve as a good starting point from which to explore the possible contribution of object orientation to distributed and concurrent programming. A contract (as introduced in section contracts) describes the interface of an object and specifies the duties and benefits for a client in terms of (logical) pre- and post-conditions.

Active objects

-- distributed programming
slide: Active objects

A similar specification may be used to describe the interaction between a client and a server in a distributed environment. In such an environment, a server is generally a process waiting for some request from a client. When such a request is received, the server spawns off a process to handle the transaction with the client and then continues to wait for requests. Often, in addition to waiting for requests, a server has responsibility of its own. For example, in the case of a printer server, the server needs to check whether the printers to which it is coupled are still in operation. In abnormal situations, a server may hold the requests until the situation is restored to normal. Despite the server's own activity, for a client a server is just an entity offering a collection of services. Hence, as observed in  [Meyer93], logically the distinction between active and passive objects need play no role. Operationally, however, the distinction between passive and active objects should be clear. A passive object uses the processing resources of the caller to execute the method invoked, whereas an active object possesses its own processing resources to deal with the request. Consequently, the implementation language must provide constructs which allow the programmer to deal (either implicitly or explicitly) with the concurrency issues involved. Which primitives are needed depends upon several factors, among which is the choice of a particular concurrency model (suiting the application domain in question). Given the availability of wide and local area networks, it seems likely that complex systems will become increasingly distributed in nature and, hence, active objects will be the rule rather than an exception. An important consequence of the accessibility of networks, in conjunction with the growing size of systems, is that (large) systems will tend to become more and more heterogeneous. For example, multi-media systems are usually not built as a single monolithic program, but rather consist of a number of smaller cooperating components, that may in their turn rely on third party software to actually display the (multimedia) documents.

Concurrent problem solving

From a modeling perspective, the availability of processes may lead to a more flexible, not to say natural, approach to problem solving. Having a notion of processes (or active objects) at one's disposal, may lead to employing the inherent concurrency characteristics of a problem domain to arrive at a more natural (that is intuitively suitable) model.

Problem solving

-- concurrency
slide: Concurrent problem solving

Traditionally, three patterns of concurrent problem solving can be distinguished, which may be characterized as pipe-line concurrency, divide and conquer, and cooperative problem solving. See slide 6-c-p-s. Pipe-line concurrency may be used to apply a sequence of filters sorting out a good solution. A well-known example of this kind of concurrency is the implementation of the sieve of Eratosthenes as a (dynamically growing) sequence of communicating processes, each testing for divisibility by a prime number. As a remark, pipe-line concurrency is also a well-known composition mechanism of the Unix operating system, where it is used to connect programs that each perform a specific operation on a stream of (character-based) data. Divide and conquer is an almost equally well-established technique of exploiting the parallelism inherent in a problem solution. The basic idea is to split a problem into relatively independent subproblems that may be solved in parallel. This subdivision may be repeated recursively. As an example of this approach, think of a parallel implementation of a sorting algorithm (for example mergesort) which consists of splitting the list to be sorted in two halves that may be sorted independently before being merged. Although this approach is straightforward, actual speedup may be hard to achieve. The final pattern (or paradigm) may be characterized as cooperative problem solving. However, this characterization actually begs the question. In contrast to the two previous patterns, which employ a regular structure of processes (respectively a sequence for pipe-lining and a tree structure for divide and conquer), the process structure employed in cooperative problem solving may be arbitrarily complex. It is this kind of modeling we are interested in when discussing object-based concurrency. Actually, this kind of cooperation comes closer to a peer-to-peer relation than the master-slave relation characteristic for the client/server model. Hence, the notion of client and server must be taken in a relative sense, as reversible roles. As an aside, as an area in which cooperative processes play an important role (as a modeling vehicle) we may mention discrete event simulation, which, historically, lies at the root of object-oriented programming.