Principles of Object-Oriented Software Development
[] readme course preface 1 2 3 4 5 6 7 8 9 10 11 12 appendix lectures resources

talk show tell print

Paradigms of programming


In a landmark paper with the title `What is object-oriented programming?' Bjarne Stroustrup raises the question of when a language may be considered to support a particular style of programming,  [St88]. See slide 1-styles.

Object-oriented programming

  • high tech synonym for good

Styles of programming

  • A language supports a style of programming if it provides facilities that make it convenient (easy, safe and efficient) to use that style

  • compile/runtime checks
  • clean interpretation/ orthogonal / efficient / minimal

slide: Styles of programming

In general, one can say that a language supports a particular style of programming if it provides facilities, both syntactic and semantic, that makes it convenient (that is easy, safe and efficient) to use that style. The crucial distinction that must be made in this context is that between allowing a certain style and providing support for that style. Allowing means that it is possible to program in that style. To support a given style, however, requires in addition that suitable compile and runtime checks are provided to enforce a proper use of the relevant language constructs. With these considerations in mind, one could question the assertion that Ada is object-oriented or that Modula supports abstract data types. Naturally, this attitude backfires with C++. Does C++ support abstract data types and is it really object-oriented?

Procedural programming

  • procedures, use the optimal algorithms


  • hide the data, provide functional abstractions

Data abstraction

  • types, provide a sufficiently complete set of operations

Object-oriented -- organize your types

  • make commonality explicit by using inheritance

slide: Paradigms of programming

It is equally important to establish whether a language allows a clean interpretation of the constructs introduced, whether the constructs supporting object orientation are orthogonal to (that is independent of) the other constructs of the language, whether an efficient implementation of these constructs is possible, and whether the language is kept minimal, that is without superfluous constructs. Before establishing what the main ingredients of object-orientation are, let us briefly look at some of the styles of programming that may be considered as leading to an object-oriented style. See slide 1-paradigms. In his article, Stroustrup (1988) stresses the continuity between the respective styles of programming pictured in slide 1-paradigms. Each style is captured by a short phrase stating its principal concern, that is guidelines for developing good programs.

Procedural programming

The procedural style of programming is most closely related to the school of structured programming, of which for instance  [
Dijkstra76] and  [Gries] are important proponents. The procedural style supports a method of program development that is known as stepwise refinement. Stepwise refinement is an important heuristic for developing complex algorithms. Instead of writing out a complex algorithm in all its detail, the method allows for refining the elementary steps of the basic algorithm by means of increasingly detailed procedures.

  while ( programming == art )  {
  	incr( pleasure );
  	decr( bugs );
  	incr( portability );
  	incr( maintainability );
  	incr( quality );
  	incr( salary );
  } // live happily ever after

slide: Programming as an art

As a playful example of this style of programming, consider the fragment that may be found on the cover of  [Knuth92]. See slide 1-art. Ignoring the contents, clearly the structure shows an algorithm that is conceived as the repeated execution of a number of less complex steps.

Data abstraction

When programs became larger and data more complex, the design of correct algorithms was no longer the primary concern. Rather, it became important to provide access to data in a representation independent manner. One of the early proponents of data hiding was, see  [
Parnas72a] and  [Parnas72b], who introduced a precursor to the notion of data abstraction as it has become popular in object-oriented languages such as Smalltalk or C++. As a language that supports data hiding, we may think of Modula-2 that offers strong support for modules and the specification of import and export relations between modules. Also the package construct of Ada provides support for data hiding. See slide 1-abstraction. Modules as provided by Modula-2 and Ada give a syntactic means for decomposing a program into more or less independent components. It is precisely the purely syntactic nature of modules that may be considered the principal defect of this approach to data hiding. Semantically, modules provide no guideline with respect to how to decompose a program into meaningful components.

Support for data abstraction

  • Abstract Data Types -- encapsulation


  • initialization
  • protection
  • coercions

slide: Data abstraction

To express the meaning of a module, we need the stronger notion of types, in the sense of abstract data types which are characterized by a set of operations. The notion of types as for example supported in CLU,  [Liskov74], enables us to determine whether our decomposition satisfies certain formal criteria. For instance, we may ask whether we have defined sufficiently many operations for a given type and whether we have correctly done so. An important advantage of using abstract data types is that we can often find a mathematical model that formally characterizes the behavior of that type. From the perspective of formal methods, data abstraction by means of abstract data types may be considered as one of the principal means for the specification and verification of complex software systems. See also sections adt-modules and formal-coop. From an implementation perspective, to support data abstraction a language must provide constructs to implement concrete realizations of abstract data types. Such support requires that means are provided to create and initialize elements of a concrete type in a safe way, and that vulnerable data is effectively protected. Very important is the possibility of defining generic types, that is types which take a (type) parameter with which they are instantiated. For example, the definition of a stack does not differ for a stack of integers, a stack of strings or a stack of elements from an arbitrary user-defined type.

Object-oriented programming

There is a close similarity between the object model as presented earlier and the notion of abstract data types just described. Both objects and abstract data types define a set of applicable operations that completely determine the behavior of an object or an element of the data type. To relate an object to an abstract data type we need the notion of class, that serves as the description on an abstract level of the behavior of (a collection of) objects. (The objects are called the instances of the class.) As noted in  [
St88], abstract data types as such, although mathematically satisfying, are rather inflexible and inconvenient for specifying complex software systems. To attain such flexibility, we need to be able to organize our types and express the commonality between them. The notion of class supports this by a mechanism called inheritance. When regarding classes as types, inheritance may be seen as introducing polymorphic types. A class that is derived from a particular class (the base class) may be treated by the compiler as a subtype of (the type of) that particular class. See slide 1-oo-support.

Support for OOP

  • Polymorphism -- inheritance


  • dynamic binding
  • protection
  • multiple inheritance

slide: Support for OOP

Operationally, the power of inheritance comes from message dispatching. This mechanism is called dynamic binding. Message dispatching takes care of selecting the right method in response to a message or method call. In a hierarchy of (derived) classes, a method for an object may be either defined within the class of the object itself or by one of the classes from which that class is (directly or indirectly) derived. Message dispatching is an essential mechanism for supporting polymorphism, since it allows to choose the most appropriate behavior for an object of a given type. This must occur at runtime, since the type of an object as determined at compile-time may be too general. An important issue in determining whether a language supports object-oriented programming is whether it offers a protection mechanism to shield the vulnerable parts of a base class from the classes that derived from that class. Another question of interest is whether a language must support multiple inheritance. Clearly, there is some disagreement on this issue. For example, Smalltalk-80 and Java do not support multiple inheritance. The Eiffel language, on the other hand, supported multiple inheritance from its first days. For C++, multiple inheritance was introduced at a later stage. At first, it was thought to be expensive and not really necessary. Closer analysis, however, revealed that the cost was not excessive. (See Ellis and Stroustrup, 1990.) The issue of multiple inheritance is still not resolved completely. Generally, it is acknowledged to be a powerful and at the same time natural extension of single inheritance. However, the inheritance mechanism itself seems to be under attack. Some doubt remains as to whether inheritance is a suitable composition mechanism when regarded from the perspective of reuse and reliability.

An elegant solution is provided by Java which offers multiple interface inheritance, by allowing multiple interfaces to be realized by an actual class.

[] readme course preface 1 2 3 4 5 6 7 8 9 10 11 12 appendix lectures resources

draft version 0.1 (15/7/2001)