topical media & game development
object-oriented programming
Paradigms of programming
subsections:
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 {\em 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
Modules
- 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
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
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.
(C) Æliens
04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.