An Overview of the Main Course Themes

Steven J Zeil

Contents:

1 OO in Programming and Design

This course is concerned with object-oriented programming (OOP), design (OOD), and analysis (OOA). Clearly, with so much of this OO stuff flying around, it would be nice if we had an idea of what an object is, and just what is meant by “object-oriented”.

1.1 Observations on Pre-OO Programming Languages

The Roots of OOP

OO programming and design have their roots in simulation. In the late 1960s, the population of programmers was dominated by people who had switched fields, typically from the mathematics or physical sciences, rather than people who had originally trained in computer science. Indeed, academic programs in computer science were far less common than they are today, and tended to treat CS as more of a tool to be applied to application areas rather than as a field of study in its own right. Commonly, a CS degree program would offer two tracks - business programming and scientific programming.

One of the more active and exciting application areas at the time was simulation. Programmers in this area began to recognize common patterns arising over and over in their code. A number of code libraries were designed and distributed that attempted to capture and simplify these common simulation tasks. Eventually, special-purpose simulation programming languages were developed.

There was ample precedence for this kind of specialization. The dominant languages of the time were generally perceived as tailored to specific applications: FORTRAN and APL for science applications, COBOL for business, LISP for A.I., SNOBOL for text/string processing, etc. Any of these languages could have been used for other kinds of applications, but it was certainly easier to work with a language that matched well with the application area.

Simula (1967) is now the best known of those special purpose simulation languages. In what seemed “natural” to someone writing simulations, Simula allowed a programmer to organize a simulation program in terms of a world of objects that interacted with one another via programmed behaviors. What could seem more natural to someone writing a simulation of some part of the real world?

1.2 Tension in Pre-OO Programming Languages

The history of programming languages and of design can be viewed as a continual contest against increasing complexity of software systems:

Problem: too many … Response Useful?
… statements nesting ( { … } ) OK
gather statements into functions OK
… functions nesting inadequate
gather functions into subsystems / “modules” Too loosely defined
gather functions into encapsulated ADTs Good
… ADTs Gather into namespaces/packages Not much help
Organize loosely into inheritance hierarchies The OO approach

Meanwhile, back in the “main stream” of programming language development, one of the main historic trends has always been trying to keep programs well organized even as programs get larger and larger. The earliest and simplest way to cope with size was to allow individual statements to be grouped together into functions/procedures/subroutines (all effectively meaning the same thing). In fact this idea pre-dates high-level programming languages, being implicit in the machine code instruction sets of almost all CPUs ever built. It may even pre-date any actual programming. Some attribute this idea to Ada Lovelace’s programs for Babbage’s never-constructed analytical engine.

Functions allow us to cope when the number of individual statements in a program grows so large as to be unwieldy. So what do we do when the number of functions grows too large to be manageable? Programmers and designers tried to cope by grouping functions into “modules” or “subsystems”. These groupings were little more than a matter of documentation and physical arrangement of the functions within the source code files. On a team project, a single person who did not want to “play nice” could easily wreak havoc.

A more solid organizing principle arose in the notion of an Abstract Data Type (ADT). We’ll review this concept in more detail in a later lesson, but an ADT groups together a data type name and a collection of functions for manipulating data of that type.

ADTs were something of a revolution in programming, as they often led to remarkably clean, reusable modules. Of course, like all modules, the ADT originally was implemented simply by documenting it as such: “the functions in this file provide the ADT Stack…” An uncooperative team member could often compromise this organization (usually giving plausible but short-sighted excuses such as “I could get the program done faster if I bypassed that” or “It runs a millisecond faster if I access that bit of data directly instead of using those functions”).

The value of ADTs became widely accepted, and programming language designers responded by adding support for them into new programming languages. Languages such as Modula 2 (1970) and Ada (1983) added language mechanisms (called a “module” and a “package”, respectively) for grouping types and functions together. Both enforced “information hiding” by encapsulating portions of an ADT implementation that other programmers would then be unable to access without incurring compilation errors.

Many writers incorrectly regard ADTs, encapsulation, and information hiding as innovations of OOP, but in fact these ideas had been around for some time earlier, and were in widespread use before object-oriented programming languages (OOPL) made their entrance.

Indeed, we will eventually see that the vast majority of code written by even the very best programmers working in an OOPL is not particularly OO, but will exploit encapsulated ADTs very heavily.

1.3 Pre-OO Design Techniques

Observations

OK, let’s agree that a good ADT is a wonderful thing. Just where do good ADTs come from? Or, to put it another way, when you are designing a program, how do you figure out which ADTs you should use?

If you search the web for the term “abstract data type”, you will find lots of examples of things you might pull out of a library of data structures: stacks, queues, lists, etc. It’s easy to get the impression that an ADT is something that someone else provides for you as a convenient little package of code.

But that misses the point that “abstract data type” is an organizing principle for your own programs. ADTs for general purpose data structures are all very nice, but how do you come up with the special-purpose ADTs that organize your program in a way that is specific to the problem it solves?

Pre-OO design techniques were oriented towards functions performed by the program. For example, if you were working on automating the management of book handling in a typical library, you might start by dividing the system into major subsystems such as RecordStorage, CheckInOut, AccountMgmt, and InventoryMgmt. Under each subsystem, you would group functions to be performed, such as CheckOutBook, CheckInBook, and RenewBook under the CheckInOut subsystem, or addBook, removeBook, and transferToBranch under InventoryMgmt.

1.4 Stepwise Refinement & Top-Down Design


Stepwise Refinement Example

Automating book handling in a library:

If pre-OO designers were asked to design one of these functions, say, addBook, they would probably do so by “stepwise refinement”, a.k.a. “top-down design”.


Stepwise Refinement Example II

Suppose we wanted to design the function to add a new book to the library’s collection.

function addBook (book, branchName)
{
  bookInfo = getBookInfo(book);
  record branchName as location in bookInfo;
  addToCardCatalog (bookInfo);
  addToInventory (bookInfo, branchName);
}

Stepwise Refinement Example III

Next the designers would pick one of those rather vaguely understood lines of code in that function body and expand it, either in place or as a separate function. For example:

function addBook (book, branchName)
{
  bookInfo = getBookInfo(book);
  record branchName as location in bookInfo;
  // addToCardCatalog (bookInfo)
  add to AuthorIndex (bookInfo);
  add to SubjectIndex (bookInfo);
  add to TitleIndex (bookInfo);
  cardCatalog.addToAuthorIndex
  addToInventory (bookInfo, branchName);
}

Then, again, we would pick a vaguely understood line and expand it.


Stepwise Refinement Example IV

function addBook (book, branchName)
{
  bookInfo = getBookInfo(book);
  record branchName as location in bookInfo;
  // addToCardCatalog (bookInfo)
  //   add to AuthorIndex (bookInfo);
  authorList = bookInfo.getAuthors();
  for each author au in authorList {
    catalog.authorIndex.addByAuthor (au, bookInfo);
  }
  add to SubjectIndex (bookInfo);
  add to TitleIndex (bookInfo);
  cardCatalog.addToAuthorIndex
  addToInventory (bookInfo, branchName);
}

1.5 Top-Down Example: Observations

Now, stepwise refinement is a valuable technique. It’s still probably the technique of choice for low-level design (the design of an algorithm for a single function). But it’s not nearly so useful as a technique for high-level design (the separation fo a large problem into separate modules). Consider that, at this point in our example, we have mentioned about a dozen different function names. None of them have been associated with an ADT. What are the odds that any of them would wind up inside an ADT? Pretty slim, usually.

An experienced designer might take note that the above process gives some hints as to some potential ADTs (Book, branchLibrary, CardCatalog, etc.). But this insight is pretty much separate from the design process itself. A designer has to be somewhat schizoid, actively participating in the design while simultaneously standing aside as a detached observer, watching for hints of possible ADTs.

2 The Object-Oriented Philosophy

2.1 Program = Simulation

The Object-Oriented Philosophy


Design from the World


Real-World Relationships


Organizing the World

OO designers would start by organizing these things into ADTs, e.g.:

 


Simulate the World’s Actions

Only then would OO designers consider the specific steps required to add a book to inventory:

“update the electronic card catalog so that the book can be found, and record that the book is present in the inventory of a particular branch”


Simulate the World’s Actions

function Librarian::acquisition (Book book)
{
  BranchLibrary branch = this.assignment;
  Catalog catalog = mainLibrary.catalog;
  catalog.add (book, branch);
  branch.addToInventiory (book);
}

function Catalog::add (Book book)
{
  authorIndex.add (book);
  titleIndex.add (book);
  subjectIndex.add (book);
}


OO Approach - Observations

Technically, does the same thing as the earlier design,but

2.2 Simulation == Modeling


OO Analysis & Design


Models

We can rephrase that as


Steps in Modeling

3 Putting the “Programming” in OOP


OOP in Programming Language History

Language Concepts Examples Design Concepts
Statements Stepwise Refinement
Functions FORTRAN (1957), COBOL, ALGOL, Basic (1963), C (1969), Pascal (1972) Top-Down Design
Encapsulated modules, classes Modula, Modula 2 (1970), Ada (1983) Information hiding, ADTs
Inheritance, subtyping, dynamic binding (OOP) Smalltalk (1980), C++ (1985), Java (1995) Object-Oriented A&D

3.1 What is an Object?

Maybe you thought I was never going to get around to this?


Objects

An object is characterized by


Identity

Identity is the property of an object that distinguishes it from all others. We commonly denote identity by


State

The state of an object consists of the properties of the object, and the current values of those properties.

For example, given this list of properties:

 struct Book {
    string title;
    Author author;
    ISBN isbn;
    int edition;
    int year;
    Publisher publisher;
 };

we might describe the state of a particular book as

 Book cs330Text = {
    "Object Oriented Design & Patterns", horstmann,
    "0-471-74487-5", 2, 2006,
    wileyBooks};

Behavior

Behavior is how an object acts and reacts to operations on it, in terms of

3.2 Messages & Methods

In OOP, behavior is often described in terms of messages and methods.

A message to an object is a request for service.

A method is the internal means by which the object responds to that request.


Differing Behavior

Different objects may respond to the same message via different methods.

Example: suppose I send a message “send flowers to my grandmother” to …

3.3 What is a Class?

A class is a named collection of potential objects.

In the languages we will study,


Are Objects and Classes New

OOPL Traditional PL
object variable, constant
identity label, name, address
state value
class type (almost)
message function decl
method function body
passing a message function call

Classes versus Types

Although “class” and “type” mean nearly the same thing, they do carry a slightly different idiomatic meaning.


Instances of Multiple Types


Inheritance Example

 


What makes a PL an OOPL

.