Docsity
Docsity

Prepare for your exams
Prepare for your exams

Study with the several resources on Docsity


Earn points to download
Earn points to download

Earn points by helping other students or get them with a premium plan


Guidelines and tips
Guidelines and tips

Evolution of Abstraction in Programming: From Stacks to Objects, Lecture notes of Object Oriented Programming

A brief history of abstraction mechanisms in programming, starting from the concept of stacks and modules, and moving on to abstract data types and object-oriented programming. It discusses the importance of information hiding and the role of modules in implementing abstract data types.

Typology: Lecture notes

2021/2022

Uploaded on 09/12/2022

youcangetme
youcangetme 🇬🇧

5

(4)

214 documents

Partial preview of the text

Download Evolution of Abstraction in Programming: From Stacks to Objects and more Lecture notes Object Oriented Programming in PDF only on Docsity!

Chapter 2

Abstraction

If you op en an atlas you will often rst see a map of the world. This map will show only the most signi cant features. For example, it may show the various mountain ranges, the o cean currents, and other extremely large structures. But small features will almost certainly b e omitted. A subsequent map will cover a smaller geographical region, and will typically p ossess more detail. For example, a map of a single continent (such as South America) may now include p olitical b oundaries, and p erhaps the ma jor cities. A map over an even smaller region, such as a country, might include towns as well as cities, and smaller geographical features, such as the names of individual mountains. A map of an individual large city might include the most imp ortant roads leading into and out of the city. Maps of smaller regions might even represent individual buildings. Notice how, at each level, certain information has b een included, and certain information has b een purp osely omitted. There is simply no way to represent all the details when an artifact is viewed at a higher level of abstraction. And even if all the detail could b e describ ed (using tiny writing, for example) there is no way that p eople could assimilate or pro cess such a large amount of information. Hence details are simply left out. Fundamentally, p eople use only a few simple to ols to create, understand, or manage complex systems. One of the most imp ortant techniques is termed abstraction.

Abstraction

Abstraction is the purp oseful suppression, or hiding, of some details of a pro cess or artifact, in order to bring out more clearly other asp ects, details, or structure.

Consider the average p ersons understanding of an automobile. A laymans view of an automobile engine, for example, is a device that takes fuel as input and pro duces a rotation of the drive shaft as output. This rotation is to o fast to

26 CHAPTER 2. ABSTRACTION

connect to the wheels of the car directly, so a transmission is a mechanism used to reduce a rotation of several thousand revolutions p er minute to a rotation of several revolutions p er minute. This slower rotation can then b e used to prop el the car. This is not exactly correct, but it is suciently close for everyday purp oses. We sometimes say that by means of abstraction we have constructed a model of the actual system.

transmission 

engine

fuel

XXXXXXX
X

In forming an abstraction, or mo del, we purp osely avoid the need to un- derstand many details, concentrating instead of a few key features. We often describ e this pro cess with another term, information hiding.

Information Hiding

Information hiding is the purp oseful omission of details in the development of an abstract representation.

2.1 Layers of Abstraction

In a typical program written in the ob ject-oriented style there are many imp or- tant levels of abstraction. The higher level abstractions are part of what makes an ob ject-oriented program ob ject-oriented. At the highest level a program is viewed as a \community" of ob jects that must interact with each other in order to achieve their common goal:

A A A A A A A A
AA
XXXXXX
X
@@ H
HH
HH
28 CHAPTER 2. ABSTRACTION

Client

Server

 -

We are not using the term server in the technical sense of, say, a web server. Rather, here the term server simply means an ob ject that is providing a service. The two layers of abstraction refer to the two views of this relationship; the view from the client side and the view from the server side. In a go o d ob ject-oriented design we can describ e and discuss the services that the server provides without reference to any actions that the client may p erform in using those services. One can think of this as b eing like a billb oard advertisement:

Services O ered:

void push (Ob ject val); (^) $ Ob ject top (); (^) $ void p op (); (^) $0.

Jo e's Data Structure Warehouse \For Al l your Data Structure Needs!"

The billb oard describ es, for example, the services provided by a data struc- ture, such as a Stack. Often this level of abstraction is represented by an inter- face, a class-like mechanism that de nes b ehavior without describing an imple- mentation:

interface Stack f public void push (Object val); public Object top () throws EmptyStackException; public void pop () throws EmptyStackException; g

2.1. LAYERS OF ABSTRACTION 29

Finding the Right Level of Abstraction

In early stages of software development a critical problem is nding the right level of abstraction. A common error is to dwell on the lowest levels, worrying ab out the implementation details of various key comp onents, rather than striving to ensure that the high level organizational structure promotes a clean separation of concerns. The programmer (or, in larger pro jects, the design team) must walk a ne line in trying to identify the right level of abstraction at any one p oint of time. One do es not want to ignore or throw away to o much detail ab out a problem, but also one must not keep so much detail that imp ortant issues b ecome obscured.

The next level of abstraction lo oks at the same b oundary but from the server side. This level considers a concrete implementation of the abstract b ehavior. For example, there are any numb er of data structures that can b e used to satisfy the requirements of a Stack. Concerns at this level deal with the way in which the services are b eing realized.

public class LinkedList implements Stack ... f public void pop () throws EmptyStackException f ... g ... g

Finally, the last level of abstraction considers a single task in isolation; that is, a single metho d. Concerns at this level of abstraction deal with the precise sequence of op erations used to p erform just this one activity. For example, we might investigate the technique used to p erform the removal of the most recent element placed into a stack. public class LinkedList implements Stack ... f ... public void pop () throws EmptyStackException f if (isEmpty()) throw new EmptyStackException(); removeFirst(); // delete rst element of list g ... g

Each level of abstraction is imp ortant at some p oint during software develop- ment. In fact, programmers are often called up on to quickly move back and forth b etween di erent levels of abstraction. We will see analysis of ob ject-oriented

2.2. OTHER FORMS OF ABSTRACTION 31

bicycle

^ @@

wheeled vehicle

automobile

means of transportation HH H pack horse

Figure 2.2: Layers of Sp ecialization

Is-a and Has-a Abstraction

The ideas of division into parts and division into sp ecializations represent the two most imp ortant forms of abstraction used in ob ject-oriented programming. These are commonly known as is-a and has-a abstraction. The idea of division into parts is has-a abstraction. The meaning of this term is easy to understand; a car \has-a" engine, and it \has-a" transmission, and so on. The concept of sp ecialization is referred to as \is-a" abstraction. Again, the term comes from the English sentences that can b e used to illustrate the relationships. A bicycle \is-a" wheeled vehicle, which in turn \is-a" means of transp ortation. Both is-a and has-a abstractions will reapp ear in later chapters and b e tied to sp eci c programming language features.

oriented languages make extensive use of this form of abstraction.

Yet another form of abstraction is to provide multiple views of the same artifact. Each of the views can emphasize certain detail and suppress others, and thus bring out di erent features of the same ob ject. A laymans view of a car, for example, is very di erent from the view required by a mechanic.

2.2.1 Division into Parts

The most common technique p eople use to help understand complex systems is to combine abstraction with a division into comp onent parts. Our description of an automobile is an example of this. The next level of understanding is then achieved by taking each of the parts, and p erforming the same sort of analysis at a ner level of detail. A slightly more precise description of an engine, for example, views it as a collection of cylinders, each of which converts an explosion of fuel into a vertical motion, and a crankshaft, which converts the up and down motion of the cylinder into a rotation.

32 CHAPTER 2. ABSTRACTION
B
B
B
B
B
B

Another example might b e organizing information ab out motion in a human b o dy. At one level we are simply concerned with mechanics, and we consider the b o dy as comp osed of b one (for rigidity), muscles (for movement), eyes and ears (for sensing), the nervous system (for transferring information) and skin (to bind it all together). At the next level of detail we might ask how the muscles work, and consider issues such as cell structure and chemical actions. But chemical actions are governed by their molecular structure. And to understand molecules we break them into their individual atoms. Any explanation must b e phrased at the right level of abstraction; trying to explain how a p erson can walk, for example, by understanding the atomic level details is almost certainly dicult, if not imp ossible.

2.2.2 Encapsulation and Interchangeability

A key step in the creation of large systems is the division into comp onents. Supp ose instead of writing software, we are part of a team working to create a new automobile. By separating the automobile into the parts engine and transmission, it is p ossible to assign p eople to work on the two asp ects more or less indep endently of each other. We use the term encapsulation to mean that there is a strict division b etween the inner and the outer view; those memb ers of the team working on the engine need only an abstract (outside, as it were) view of the transmission, while those actually working on the transmission need the more detailed inside view. An imp ortant b ene t of encapsulation is that it p ermits us to consider the p ossibility of interchangeability. When we divide a system into parts, a desirable goal is that the interaction b etween the parts is kept to a minimum. For example, by encapsulating the b ehavior of the engine from that of a transmission we p ermit the ability to exchange one typ e of engine with another without incurring an undue impact on the other p ortions of the system. For these ideas to b e applicable to software systems, we need a way to discuss the task that a software comp onent p erforms, and separate this from the way in which the comp onent ful lls this resp onsibility.

34 CHAPTER 2. ABSTRACTION

Chris Fred @ @ Robin's Florist

Wholesaler

Flower Arranger

E
E
E
E
E
E

Robin^ Delivery^ Person

Grower



Gardeners

C

C

Each memb er of the community is providing a service that is used by other memb ers of the group. No memb er could solve the problem on their own, and it is only by working together that the desired outcome is achieved.

2.2.5 Comp osition

Comp osition is another p owerful technique used to create complex structures out of simple parts. The idea is to b egin with a few primitive forms, and add rules for combining forms to create new forms. The key insight in comp osition is to p ermit the combination mechanism to b e used b oth on the new forms as well as the original primitive forms. A go o d illustration of this technique is the concept of regular expressions. Regular expressions are a simple technique for describing sets of values, and have b een extensively studied by theoretical computer scientists. The description of a regular expression b egins by identifying a basic alphab et, for example the letters a, b, c and d. Any single example of the alphab et is a regular expression. We next add a rule that says the comp osition of two regular expressions is a regular expression. By applying this rule rep eatedly we see that any nite string of letters is a regular expression:

abaccaba

The next combining rule says that the alternation (represented by the vertical bar j) of two regular expressions is a regular expression. Normally we give this rule a lower precedence that comp osition, so that the following pattern represents the set of three letter values that b egin with ab, and and end with either an a, c or d:

aba j ab c j ab d

Parenthesis can b e used for grouping, so that the previous set can also b e de- scrib ed as follows:

ab(ajcjd)

Finally the  symb ol (technically known as the kleene-star) is used to represent the concept \zero or more rep etitions". By combining these rules we can describ e quite complex sets. For example, the following describ es the set of values that b egin with a run of a's and b's followed by a single c, or a two character sequence dd, followed by the letter a.

2.2. OTHER FORMS OF ABSTRACTION 35

(((ajb)*c)jdd)a

This idea of comp osition is also basic to typ e systems. We b egin with the primitive typ es, such as int and b o olean. The idea of a class then p ermits the user to create new typ es. These new typ es can include data elds constructed out of previous typ es, either primitive or user-de ned. Since classes can build on previously de ned classes, very complex structure can b e constructed piece by piece.

class Box f // a b ox is a new data typ e ... private int value; // built out of the existing typ e int g

Yet another application of the principle of comp osition is the way that many user interface libraries facilitate the layout of windows. A window is comp osed from a few simple data typ es, such as buttons, sliders, and drawing panels. Various di erent typ es of layout managers create simple structures. For example, a grid layout de nes a rectangular grid of equal sized comp onents, a b order layout manger p ermits the sp eci cation of up to ve comp onents in the north, south, east, west, and center of a screen. As with regular expressions, the key is that windows can b e structured as part of other windows. Imagine, for example, that we want to de ne a window that has three sliders on the left, a drawing panel in the middle, a bank of sixteen buttons organized four by four on the right, and a text output b ox running along the top. (We will develop just such an application in Chapter 22. A screen shot is shown in Figure 22.4.) We can do this by laying simple windows inside of more complex windows (Figure 2.3). Many computer programs can themselves b e considered a pro duct of comp o- sition, where the metho d or pro cedure call is the mechanism of comp osition. We b egin with the primitive statements in the language (assignments and the like). With these we can develop a library of useful functions. Using these functions as new primitives, we can then develop more complex functions. We continue, each layer b eing built on top of earlier layers, until eventually we have the desired application.

2.2.6 Layers of Sp ecialization

Yet another approach to dealing with complexity is to structure abstraction using layers of sp ecialization. This is sometimes referred to as a taxonomy. For exam- ple, in biology we divide living things into animals and plants. Living things are then divided into vertebrates and invertebrates. Vertebrates eventually includes mammals, which can b e divided into (among other categories) cats and dogs, and so on. The key di erence b etween this and the earlier abstraction is that the more sp ecialized layers of abstraction (for example, a cat) is indeed a representative

2.2. OTHER FORMS OF ABSTRACTION 37

Object

Button Checkb ox Choice

Comp onent

Container Lab el List Scrollbar Canvas  

Q
QQ
XXXXXXX
X

TextComp onent  

Q
QQ

Panel Window ScrollPanel  

Q
QQ

TextArea TextField Dialog^ Frame

Figure 2.4: The AWT class hierarchy

of the more general layer of abstraction (for example, an animal). This was not true when, in an earlier example, we descended from the characterization of a muscle to the description of di erent chemical interactions. These two di erent typ es of relations are sometimes describ ed using the heuristic keywords \is-a" and \has-a". The rst relationship, that of parts to a whole, is a has-a relation, as in the sentence \a car has an engine". In contrast, the sp ecialization relation is describ ed using is-a, as in \a cat is a mammal".

But in practice our reason for using either typ e of abstraction is the same. The principle of abstraction p ermits us to suppress some details so that we can more easily characterize a fewer numb er of features. We can say that mammals are animals that have hair and nurse their young, for example. By asso ciating this fact at a high level of abstraction, we can then apply the information to all more sp ecialized categories, such as cats and dogs.

The same technique is used in ob ject-oriented languages. New interfaces can b e formed from existing interfaces. A class can b e formed using inheritance from an existing class. In doing so, all the prop erties (data elds and b ehavior) we asso ciate with the original class b ecome available to the new class.

In a case study later in this b o ok we will examine the Java AWT (Abstract Windowing To olkit) library. When a programmer creates a new application using the AWT they declare their main class as a sub class of Frame, which in turn is linked to many other classes in the AWT library (Figure 2.4). A Frame is an sp ecial typ e of application window, but it is also a more sp ecialized typ e of the general class Window. A Window can hold other graphical ob jects, and is hence a typ e of Container. Each level of the hierarchy provides metho ds used by those b elow. Even the simplest application will likely use the following:

38 CHAPTER 2. ABSTRACTION

setTitle(String) inherited from class Frame setSize(int, int) inherited from class Comp onent show() inherited from class Window repaint() inherited from class Comp onent paint() inherited from Comp onent, then overridden in the programmers new application class

2.2.7 Patterns

When faced with a new problem, most p eople will rst lo ok to previous problems they have solved that seem to have characteristics in common with the new task. These previous problems can b e used as a mo del, and the new problem attacked in a similar fashion, making changes as necessary to t the di erent circumstances.

This insight lies b ehind the idea of a software pattern. A pattern is nothing more than an attempt to do cument a proven solution to a problem so that future problems can b e more easily handled in a similar fashion. In the ob ject-oriented world this idea has b een used largely to describ e patterns of interaction b etween the various memb ers of an ob ject community.

A simple example will illustrate this idea of a pattern. Imagine one is devel- oping an application that will op erate over a network. That means that part of the application will run on one computer, and part will run on another computer linked by a network connection. Creating the actual connection b etween the two computers, and transmitting information along this connection, are details that are p erhaps not relevant to large p ortions of the application. One way to struc- ture these relationships is to use a typ e of pattern termed a proxy. The proxy is an intermediary that hides the network connection. Ob jects can interact with the proxy, and not b e aware that any typ e of network connection is involved at all. When the proxy receives a request for data or action, it bundles the request as a package, transmits the package over the network, recieves the resp onse, un- packages the resp onse and hands it back to the client. In this fashion the client is completely unaware of the details of the network proto col.

Client Proxy^  Server

Q
QQ

Notice how the description of the pattern has captured certain salient p oints of the interaction (the need to hide the communication proto col from the client) while omitting many other asp ects of the interaction (for example, the particular information b eing communicated b etween client and server). We will have more to say ab out patterns later in Chapter 24.

40 CHAPTER 2. ABSTRACTION

int datastack[100]; int datatop = 0;

void init() f datatop = 0; g

void push(int val) f if (datatop < 100) datastack [datatop++] = val; g

int top() f if (datatop > 0) return datastack [datatop - 1]; return 0; g

int pop() f if (datatop > 0) return datastack [--datatop]; return 0; g

Figure 2.5: { Failure of pro cedures in information hiding.

did not need to know the exact details of the implementation{they needed only the necessary interface. But pro cedures were not an answer to all problems. In particular, they were not an e ective mechanism for information hiding, and they only partially solved the problem of multiple programmers making use of the same names.

Example{A Stack

To illustrate these problems, we can consider a programmer who must write a set of routines to implement a simple stack. Following go o d software engineering principles, our programmer rst establishes the visible interface to her work{say, a set of four routines: init, push, p op, and top. She then selects some suitable implementation technique. There are many choices here, such as an array with

2.3. A SHORT HISTORY OF ABSTRACTION MECHANISMS* 41

a top-of-stack p ointer, a linked list, and so on. Our intrepid programmer se- lects from among these choices, then pro ceeds to co de the utilities, as shown in Figure 2.5. It is easy to see that the data contained in the stack itself cannot b e made lo cal to any of the four routines, since they must b e shared by all. But if the only choices are lo cal variables or global variables (as they are in early programming languages, such as FORTRAN, or in C prior to the intro duction of the static mo di er), then the stack data must b e maintained in global variables. However, if the variables are global, there is no way to limit the accessibility or visibility of these names. For example, if the stack is represented in an array named datastack, this fact must b e made known to all the other programmers since they may want to create variables using the same name and should b e discouraged from doing so. This is true even though these data values are imp ortant only to the stack routines and should not have any use outside of these four pro cedures. Similarly, the names init, push, p op, and top are now reserved and cannot b e used in other p ortions of the program for other purp oses, even if those sections of co de have nothing to do with the stack routines.

2.3.3 Mo dules

The solution to the problem of global name space congestion was the intro duction of the idea of a mo dule. In one sense, mo dules can b e viewed simply as an improved technique for creating and managing collections of names and their asso ciated values. Our stack example is typical, in that there is some information (the interface routines) that we want to b e widely and publicly available, whereas there are other data values (the stack data themselves) that we want restricted. Stripp ed to its barest form, a module provides the ability to divide a name space into two parts. The public part is accessible outside the mo dule; the private part is accessible only within the mo dule. Typ es, data (variables), and pro cedures can all b e de ned in either p ortion. A mo dule encapsulation of the Stack abstraction is shown in Figure 2.6. David Parnas, who p opularized the notion of mo dules, describ ed the following two principles for their prop er use:

  1. One must provide the intended user with all the information needed to use the mo dule correctly, and nothing more.
  2. One must provide the implementor with all the information needed to complete the mo dule, and nothing more. The philosophy is much like the military do ctrine of \need to know"; if you do not need to know some information, you should not have access to it. This explicit and intentional concealment of information is what we have b een calling information hiding. Mo dules solve some, but not all, of the problems of software development. For example, they will p ermit our programmer to hide the implementation details of her stack, but what if the other users want to have two (or more) stacks?
2.3. A SHORT HISTORY OF ABSTRACTION MECHANISMS* 43

and top. Matched with the ADT will b e one or more di erent implementations. There might b e several di erent implementation techniques for our stack; for example one using an array and another using a linked list. As long as the programmer restricts themselves to only the abstract sp eci cation, any valid implementation should work equally well. The imp ortant advance in the idea of the ADT is to nally separate the notions of interface and implementation. Mo dules are frequently used as an implementation technique for abstract data typ es, although we emphasize that mo dules are an implementation technique and that the abstract data typ e is a more theoretical concept. The two are related but are not identical. To build an abstract data typ e, we must b e able to:

  1. Exp ort a typ e de nition.
  2. Make available a set of op erations that can b e used to manipulate instances of the typ e.
  3. Protect the data asso ciated with the typ e so that they can b e op erated on only by the provided routines.
  4. Make multiple instances of the typ e. As we have de ned them, mo dules serve only as an information-hiding mech- anism and thus directly address only list items 2 and 3, although the others can b e accommo dated via appropriate programming techniques. Packages, found in languages such as CLU and Ada, are an attempt to address more directly the issues involved in de ning abstract data typ es. In a certain sense, an ob ject is simply an abstract data typ e. People have said, for example, that Smalltalk programmers write the most \structured" of all programs b ecause they cannot write anything but de nitions of abstract data typ es. It is true that an ob ject de nition is an abstract data typ e, but the notions of ob ject-oriented programming build on the ideas of abstract data typ es and add to them imp ortant innovations in co de sharing and reusability.

2.3.5 A Service-Centered View

Assembly language and pro cedures as abstraction mechanisms concentrated the programmers view at the functional level{how a task should b e accomplished. The movement towards mo dules and ADT are indicative of a shift from a function-centered conception of computation to a more data-centered view. Here it is the data values that are imp ortant, their structure, representation and ma- nipulation. Ob ject-oriented programming starts from this data-centered view of the world and takes it one step further. It is not that data abstractions, p er se, are imp or- tant to computation. Rather, an ADT is a useful abstraction b ecause it can b e de ned in terms of the service it o ers to the rest of a program. Other typ es of abstractions can b e similarly de ned, not in terms of their particular actions or their data values, but in terms of the services they provide.

44 CHAPTER 2. ABSTRACTION

Assembly Language Function Functions and Pro cedures Centered View Mo dules Data Abstract Data Typ es Centered View Ob ject-Oriented Service Programming Centered View

Thus, ob ject-oriented programming represents a third step in this sequence. From function centered, to data centered, and nally to service centered view of how to structure a computer program.

2.3.6 Messages, Inheritance, and Polymorphism

In addition to this service-centered view of computing, ob ject-oriented program- ming adds several imp ortant new ideas to the concept of the abstract data typ e. Foremost among these is message passing. Activity is initiated by a request to a sp eci c ob ject, not by the invoking of a function. Implicit in message passing is the idea that the interpretation of a message can vary with di erent ob jects. That is, the b ehavior and resp onse that the message elicit will dep end up on the ob ject receiving it. Thus, push can mean one thing to a stack, and a very di erent thing to a mechanical-arm controller. Since names for op erations need not b e unique, simple and direct forms can b e used, leading to more readable and understandable co de. Finally, ob ject-oriented programming adds the mechanisms of inheritance and polymorphism. Inheritance allows di erent data typ es to share the same co de, leading to a reduction in co de size and an increase in functionality. Poly- morphism allows this shared co de to b e tailored to t the sp eci c circumstances of individual data typ es. The emphasis on the indep endence of individual comp o- nents p ermits an incremental development pro cess in which individual software units are designed, programmed, and tested b efore b eing combined into a large system. We will describ e all of these ideas in more detail in subsequent chapters.

Chapter Summary

People deal with complex artifacts and situations every day. Thus, while many readers may not yet have created complex computer programs, they neverthe- less will have exp erience in using the to ols that computer scientists employ in managing complexity.

 The most basic to ol is abstraction, the purp oseful suppression of detail in order to emphasize a few basic features.

 Information hiding describ es the part of abstraction in which we intention- ally cho ose to ignore some features so that we can concentrate on others.