Top Banner
The anguish of the programming teacher on the verge of becoming object-oriented Pedro Guerreiro Departamento de Informática Faculdade de Ciências e Tecnologia Universidade Nova de Lisboa 2825 MONTE DE CAPARICA, Portugal email: [email protected] Abstract Teachers of programming are lucky in that they do not have to do the same thing every year. Programming is still an evolving discipline, with new ideas coming forward at a steady pace. Some of those ideas can be incor- porated into the course, some even at the introductory level. Object-oriented program- ming is one of those ideas. There is no reason to believe that it will be the last, or that it will immediately make everything else obsolete. For the programming teacher, the issue is how to add object programming to a curriculum already full with interesting material, in an appealing way, that will help students make a better job, so that they can become better equipped for the “real world”. 1. Introduction If you are a programming teacher, and you try to keep up to date, you cannot have missed all the excitement about object-oriented program- ming. If you are wise, and you remember the past, probably you will not want to turn your courses upside down, just because so many people seem to be advocating this new paradigm. Or perhaps you are one of those who think they have been using objects for a long time, and do not understand what all those people are talking about. Objects are a simple concept, and they shouldn't be the reason for such a profound debate. Anyway, as objects become increasingly fash- ionable, you have to provide greater visibility for them in your courses. Students too, they expect you to do it. When they buy compilers for their own machines, the packages come with the sticker “object-oriented”, and they want to learn about that. So you are being pressed by three different sources: your professional environment, your students and your own conscience as a teacher who wants to provide the students with the most modern ideas. Once you decide to start addressing explicitly objects in your courses, how do you do it? Do you throw away your current courses and re- design everything, inspired by the new ideas? Do you keep them as they are now, and add a new course on object-oriented development, including analysis, design and programming? Do you simply add a new chapter on objects to the software engineering course? Or to the in- troductory programming course? I chose this last approach. It is the most con- servative of all, but it is not without difficulties. The concept of an object is simple, but as soon as you try to manipulate it in pro- grams, not just in talk, you face unexpected conflicts which make teaching harder. Students at introductory courses want useful
14

The anguish of the programming teacher on the verge of becoming object-oriented

Mar 30, 2023

Download

Documents

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: The anguish of the programming teacher on the verge of becoming object-oriented

The anguish of the programming teacher on the verge of becoming object-oriented

Pedro Guerreiro

Departamento de Informática Faculdade de Ciências e Tecnologia

Universidade Nova de Lisboa 2825 MONTE DE CAPARICA, Portugal

email: [email protected]

Abstract Teachers of programming are lucky in that they do not have to do the same thing every year. Programming is still an evolving discipline, with new ideas coming forward at a steady pace. Some of those ideas can be incor-porated into the course, some even at the introductory level. Object-oriented program-ming is one of those ideas. There is no reason to believe that it will be the last, or that it will immediately make everything else obsolete. For the programming teacher, the issue is how to add object programming to a curriculum already full with interesting material, in an appealing way, that will help students make a better job, so that they can become better equipped for the “real world”.

1. Introduction If you are a programming teacher, and you try to keep up to date, you cannot have missed all the excitement about object-oriented program-ming. If you are wise, and you remember the past, probably you will not want to turn your courses upside down, just because so many people seem to be advocating this new paradigm. Or perhaps you are one of those who think

they have been using objects for a long time, and do not understand what all those people are talking about. Objects are a simple concept, and they shouldn't be the reason for such a profound debate. Anyway, as objects become increasingly fash-ionable, you have to provide greater visibility for them in your courses. Students too, they expect you to do it. When they buy compilers for their own machines, the packages come with the sticker “object-oriented”, and they want to learn about that. So you are being pressed by three different sources: your professional environment, your students and your own conscience as a teacher who wants to provide the students with the most modern ideas. Once you decide to start addressing explicitly objects in your courses, how do you do it? Do you throw away your current courses and re-design everything, inspired by the new ideas? Do you keep them as they are now, and add a new course on object-oriented development, including analysis, design and programming? Do you simply add a new chapter on objects to the software engineering course? Or to the in-troductory programming course? I chose this last approach. It is the most con-servative of all, but it is not without difficulties. The concept of an object is simple, but as soon as you try to manipulate it in pro-grams, not just in talk, you face unexpected conflicts which make teaching harder. Students at introductory courses want useful

Page 2: The anguish of the programming teacher on the verge of becoming object-oriented

information, that will help them to become good programmers fast. So, if you want to have a successful course, you must present ob-jects in a palatable way, show that they fit with the rest, prove that although with objects things will not be simpler, with them programmers can indeed solve problems in a more effective way. In section 2, I review the evolution of teaching programming, as I have experienced it, from the times of FORTRAN to the era of objects. In section 3, I give my thoughts on the current object-oriented wave. In section 4, I describe my current course in programming and then, in section 5, the longest in this paper, I discuss the introduction of object technology in that course. I conclude, in section 6, with some re-marks about the future of objects.

2. The Past I have been teaching programming for almost fifteen years now. Hundreds of students have learned some of the basics of programming in my courses. Perhaps I have not been a good teacher, and my lessons were of no use to many of them. Perhaps I was not always able to give them the most up to date material. When the important languages were FORTRAN and COBOL, I was teaching programming in Pascal. When structured methodologies appeared, I postponed them to systems analysis courses and continued to stress structured programming and stepwise refinement. When everybody wanted fancy programming environments with colorful windows and various fonts, I was making them go through the standard edit – compile – run cycle with UNIX and vi. But I must have gained some experience. I think I know what is difficult for the students, I think I know where they get confused more often, I think I am able to guess which error they are going to make next. I think I know what should be taught first, how to explain simple ideas without offending their intelligence, how to deal with more complex issues without turning them off.

How has my teaching evolved during this decade and a half? In the beginning it was somewhat “language-oriented”. That was the way I learned programming in the late sixties with McCracken's A guide to FORTRAN IV Programming [McCracken 65]. This wonder-ful book has many case studies, but the overall approach is like this: here is a statement (GO TO, arithmetic IF, DO, FORMAT, etc.), and now let's see some examples. The first case study is a program to compute the area of a triangle, given the lengths of the sides, a, b and c, using the formula

area = s(s − a)(s − b)(s − c)

where

s =a + b + c

2

This was a time before the “Hello world” pro-gram was invented, and it certainly is a better first program for any language. I transcribe McCracken's solution: C CASE STUDY 1 - AREA OF A TRIANGLE C READ (5, 23) A, B, C 23 FORMAT (3F10.0) S = (A+B+C) / 2.0 AREA = SQRT(S * (S-A) * (S-B) * (S-C)) WRITE (6, 17) A, B, C, AREA 17 FORMAT (1P4E16.7) STOP END

I was lucky that Pascal was already around when it was my turn to teach. But I still re-member that to illustrate the for statement, I would show a piece of program that would print the first 100 positive integers. I tried to balance this language orientation with a more abstract algorithmic orientation. An idea that was popular at the time (still is, I fear) is that the language is not important, the algorithm is, and to express your algorithm you do not have to be constrained by all those arbitrary peculiarities of the language, even if the language is Pascal. Teaching algorithms per se is easy, and the students enjoy it, because they can see their stock of techniques growing. Some students may even appreciate the inherent beauty of many algorithms. The exercise will have been

Page 3: The anguish of the programming teacher on the verge of becoming object-oriented

incomplete, however, if they are not able to solve programming problems in which those algorithms play a role. This is why my teaching became problem-ori-ented. The approach was: here is a problem; what do we need to solve it by computer? When you use this approach, technique number one is: Is this problem a new problem, or just an old problem in disguise? All programmers know that the same problems keep appearing repeatedly, with tiny variations, and we do not want to start all over from the beginning everyday. Therefore, when the next problem comes in, first you try to identify which subproblems are old problems; then you ponder the really new ones. This is a reuse-oriented approach, of course, and is best supported by a language with full genericity. But Pascal also lets you il-lustrate the principles to a certain extent. For instance, you can add a functional parameter to the bubblesort procedure, specifying the de-sired order relation, and it works wonders. It is a pity, however, that you cannot parametrize the type of the array elements. If the problem you use is really a problem, stu-dents need guidance to tackle it the way you want them to do. Rule number one is the one above: look for old things. Rule number two is (or should it be number zero?): ask yourself what is this problem about. Is it about triangles in a plane, about a vending machine with soda cans and a slot where you insert coins, about workers in a company? These two rules should give the clues which students need to start working. (Is this the core of a methodology?) They can immediately col-lect the old things from old programs, and start to adapt them; and they can, all along, ponder the new problems. (Perhaps the methodology is recursive, and when you look closer at the subproblems that are new, you recognize subsubproblems that are old…) And in the meantime, they learn that what is new today will be old tomorrow. How can they program today in a way that can be useful tomorrow? By clearly distinguishing what is particular from what is general. This is hard. How can a

beginner know that a linked list is general and that an array of 255 characters is particular? There is a way out: teach the fundamental data structures (through problems, as always). They are general, and with them you can discuss many programming concepts and illustrate many programming techniques. Luckily enough, we have the abstract data type concept to guide us with the data structures. This way, our program will be built by procedures and functions that operate on data structures. Wouldn't it be excellent if we could change the data structure by a better one or the text of a routine by one that is more efficient and nobody else would notice? Enter the world of modularity and information hiding. Pascal does not help here, but if you are bold enough, you can threaten your students with Ada or with object-oriented programming.

3. The present When did these object things become menac-ing? 1988, 1989? Every time we go to a con-ference on objects, we have to endure the same old story about SIMULA 67 and Smalltalk. But weren't those mere curiosities until objects were grafted on popular lan-guages like C and Pascal? As I recall it, objects couldn't appear at a more appropriate time. They gave us a good excuse to skip Ada. We keep the old languages, and with them an advantage of years of experience over the younger generation of programmers, but we feel the satisfaction of still be riding on the crest of the wave. We have learned the lesson of structured programming: those who stuck with COBOL never caught up with Pascal and C. (Wait until COBOL gets objects too…) Anyone who dwells in the ALGOL-family territory could not avoid being overwhelmed by the propaganda for objects. As with deodorants, we were led to believe that if we do not use them we are not normal people. And our students are going to think that we are more outdated than ever if we naively and earnestly continue our teaching with languages that are more than twenty years old.

Page 4: The anguish of the programming teacher on the verge of becoming object-oriented

(FORTRAN was only fifteen years old when I started to learn it, and that was old, my teachers said.) And what about those aging postgraduates who took our programming courses four years ago, when they were young, whom we now overhear in the corridor discussing virtual functions and destructors? Isn't it a relief when we find out that the discussion is rhetorical, because when they finally have to show their programs they humbly confess that they are just using C with a little bit of objects? Even if you are skeptical as a rock, you must have learned not to dismiss an idea into which so many good minds are putting their efforts. Rarely such a wide consensus has come up in computer science. Well, has it really? Or is it just because we are in the center of a volcano and therefore we think the whole world is a volcano? You go to conferences on objects, you read magazines on objects, you buy lan-guages with objects, and you end up dreaming to believe that everything is an object. Then when you hear reports that the vast majority of programmers does not even know what an ob-ject is, you wake up to the cruel reality that things are not always what they seem. Isn't it great that after all so many people do not know an object is? This means that more preachers are needed and you can be one of them. But how do we become one? Is it enough to read Booch's books and Meyer's? Do you have to learn by heart the Smalltalk hierarchy of classes? Do you have to buy a Mac and become proficient in MacApp? Do you have to take a deep breath, forget your prejudices, and dive into C++ at last? Do you have to do all those things? Or should you start instead by object-oriented analysis, then move on to object-oriented de-sign, and on to object-oriented programming? Or should you do nothing until you decide which object-oriented CASE tool to buy? After all, you do not want your students to spend all their time scribbling on little pieces of paper, the old fashioned way, when you are about to teach them the latest discovery of computer science...

4. The course Even if I do not have all the answers, I decided to incorporate objects in my introductory pro-gramming course. I have experimented a lot with the course, of course, and I do not have to be fearful: this is just a new experiment, which I will have to review, as all the others. I will have to change some things, I will learn more as I go, but that is the way it has always been. The course has two parts, one semester each. The first part is devoted to basic concepts and the second to intermediate techniques. This is not an advanced course, but it is not an elementary one, either. Objects are not an advanced concept, and they definitely belong to an introductory course in programming. In our discipline, “advanced” means “hard to explain” or “difficult to use” and this cannot be the case for objects. If it was, they would not be so popular. The course is based on the idea that students have enough mathematical background, to un-derstand, without further ado, the concept of a function (and those other concepts that go with it: domain, range, partial function, binary rela-tion, order relation, etc.). This allows us to start by functions in programming. We do not need a functional programming language. There are plenty of simple problems that we can solve solely with functions in Pascal. For example, McCrackens's problem of the area of a triangle can be programmed like this: program Triangle; var a, b, c: Real;

function Area (side1: Real; side2: Real; side3: Real): Real; var semiperimeter: Real;

begin semiperimeter := (side1+side2+side3) / 2; Area := sqrt(semiperimeter * (semiperimeter-side1) * (semiperimeter-side2) * (semiperimeter-side3)) end;

begin write('Three sides, please: '); readln(a, b, c); writeln('Area = ', Area(a, b, c) : 4 : 2) end.

Page 5: The anguish of the programming teacher on the verge of becoming object-oriented

This way, functions appear as the basic build-ing block, not as an advanced programming concept, which they certainly are not. Through these initial problems we introduce elements of syntax, the if-then-else instruction, recursion, elementary input-output, functional parameters, top-down programming, bottom-up programming, testing. At first, functions use only elementary types, for which no explanation is needed (well, al-most no explanation…): integers, reals, Boole-ans, characters. But very soon we introduce type definitions and records, and things become more variegated. For example, we can complicate the problem of the area of the triangle, specifying that the triangle is represented by its vertices: type Point = record xCoordinate: Real; yCoordinate: Real end;

Triangle = record point1: Point; point2: Point; point3: Point; end;

function Distance (point1: Point; point2: Point): Real; begin Distance := sqrt(sqr(point1.xCoordinate - point2.xCoordinate) + sqr(point1.yCoordinate - point2.yCoordinate)) end;

function AreaOf (theTriangle: Triangle): Real; function Area (side1: Real; side2: Real; side3: Real): Real; var semiperimeter: Real;

begin semiperimeter := (side1+side2+side3) / 2; Area := sqrt(semiperimeter * (semiperimeter-side1) * (semiperimeter-side2) * (semiperimeter-side3)) end;

begin with theTriangle do AreaOf := Area(Distance(point1, point2), Distance(point2, point3), Distance(point3, point1)) end;

We do not want students to think that pro-gramming is just a different kind of mathemat-ics. Correction and reliability are important, of course, but so are modifiability, efficiency, and understandability, and these ideas are illustrated from the beginning. The second chapter of the course is on arrays. The concept is simple, and students bring it from geometry and physics. Along with arrays come loops (while, for, repeat) and algo-rithms: find the maximum of an array, search the array, sort the array. Things cannot become much more complicated unless you have files to store the results of your programs. Files are the subject of third chapter. We need only text files with fixed format, which can be processed on a line by line basis. Here is a typical problem that can be presented at this stage: At a Formula 1 Grand Prix race, the winner collects 10 points; the second, third, fourth, fifth and sixth collect 6, 4, 3, 2 points, and 1 point, respectively. Everybody else gets zero points. We have a text file with fixed format; each line contains the name of a driver and the number of points he has collected so far. This is the current standing file and is ordered by number of points. Only drivers with more than zero points appear. There is another text file, the racers file; for every driver, there is a line in this file with the driver's name and the number of his car. At the end of a given race, the program is used to compute the new standing file. The interface is simple line-by-line: the program loops six times, asking the number of the driver who ar-rived in each place, validates the entries, and then produces the new standing file. The recommended solution is simple. Load the standing file into an array, and the racers file into another array. When the operator types in a car number, check whether it exists by

Page 6: The anguish of the programming teacher on the verge of becoming object-oriented

searching it in the racers array, if so get the driver's name, and then search again in the standing array for a record with that driver's name. If you find it, add the corresponding number of points, otherwise create a new entry for the driver, with the points collected (this was the first time he arrived among the six). When the operator terminates, sort the standing array and then dump it into a file. With functions (and procedures), arrays and files, we can do anything. So, it is time to in-troduce the basics of analysis and design. You do not have to theorize a lot: just present the problem in a text that is half a page long, and everybody will appreciate some guidance on how to tackle it. The fourth chapter of the course is devoted to this issues. The approach is intuitive and informal. Standard methodolo-gies will be studied in other courses, later. By this time, students who started the course thinking that inspiration and creativity are all that counts should have changed their minds. You must know your language, you must have an idea on how to solve problems, but you also must know your basic data structures and the techniques to process them. The second part of the course is devoted to in-termediate programming techniques: sequential file processing, text processing, numerical computation and recursive data structures. Pointers appear at the very end, to use memory more efficiently, and as a tool to implement linked lists and binary trees.

5. Where do objects go? If you have a course like this, and you want to introduce objects, where should they appear? Not too late, lest the students think they are an advanced concept. Objects have methods and data, so students should be at ease with func-tions in programming and elementary data structures. The natural place seems to be at the end of part one, before you start preaching that you should not program before you do all the analysis and design (perhaps not all, but at least some of it). And what language to use? Object Pascal, al-though a minimalist object-oriented language,

is the first candidate. If Pascal has been the language of choice for teaching programming for the last 15 years, why shouldn't Object Pascal be the language for teaching object-ori-ented programming? If you are going to introduce objects as a basic concept, one that you can use anywhere, you may wish to revise your old programs and show how they become so much more interesting using object technology. Thus, it seems a good idea to take the problem of the area of the triangle, the basic array algorithms, the Formula 1 problem, and try to rejuvenate them a little with some object powder. Let us start with the triangles. Instead of having a function with a parameter of type Triangle, now each triangle is an object that knows how to compute its own area. You proceed to program the TTriangle class, as an abstraction of all triangle objects: type TTriangle = object fPoint1: TPoint; fPoint2: TPoint; fPoint3: TPoint; function Area: Real; end;

implementation function TTriangle.Area: Real; ... end;

If you, as a teacher, are so excited about this first class, you may not notice that suspicious look on your students' faces. Is all that there is: just place the functions inside the records? The problem of the triangle is a good one, be-cause you can introduce, not one, but two in-teresting classes. Perhaps students thought that those points in the triangle were records. No, no, they were objects too. Which methods are needed? At least one to compute the distance to another point: type TPoint = object fxCoordinate: Integer; fyCoordinate: Integer; function DistanceTo (theOtherPoint: TPoint): Real; end;

Page 7: The anguish of the programming teacher on the verge of becoming object-oriented

implementation function TPoint.DistanceTo (theOtherPoint: TPoint): Real; begin DistanceTo := sqrt( sqr(fxCoordinate - theOtherPoint.fxCoordinate) + sqr(fyCoordinate - theOtherPoint.fyCoordinate)) end;

Now you can understand the implementation of the function TTriangle.Area: function TTriangle.Area: Real; var semiperimeter: Real; side1: Real; side2: Real; side3: Real; begin side1 := fPoint1.DistanceTo(fPoint2); side2 := fPoint2.DistanceTo(fPoint3); side3 := fPoint3.DistanceTo(fPoint1); semiperimeter := (side1+side2+side3) / 2;

Area := sqrt(semiperimeter * (semiperimeter-side1) * (semiperimeter-side2) * (semiperimeter-side3)) end;

This may be hard to swallow. Before, we had that elegant function Distance, coming di-rectly from secondary school mathematics, and see what it has become: that ugly, asym-metric piece of program, no longer a proper function that computes a result from its argu-ments, but a method, which refers implicitly to the object to which it belongs. (Sometimes methods refer to their object explicitly by means of a strange pseudovariable called self.) Besides, if you are a conscious teacher, you must have a problem of conscience, at this point: you should at least explain that object variables are indeed pointers and that the actual objects are stored in the heap. But how can you do that, if pointers do not appear until the end of the year? The alternatives are not bright: C++, like C, is impossible to teach: the simplest operations need pointers and have side effects, and these are advanced concepts; Eiffel is teachable, but it is so software engineering-oriented that you would have to redesign your entire course. Fortunately, if you are careful, you can avoid the peculiarities of pointers, and keep the dis-

cussion at a high level. You do not have to spell out that self is a pointer. You can explain the New procedure just by saying that objects have to be created, not just declared. And you can omit entirely the destruction of objects, because your computer has plenty of memory. In fact, objects have to be declared, then cre-ated, then initialized (and then used, and then destroyed). That's too much paperwork, before we can do anything useful with them, the cyn-ics would say. You can calm down your stu-dents, reaching for aid in C++: in this serious object-oriented language, declaration, creation and initialization can be bundled together very neatly. And you can put forward the proposi-tion: “all objects should have initialization methods.” This kind of “laws” give a sense of security and maturity to the subject, and they do no harm. For points and for triangles, the initialization methods are: type TPoint = object ... procedure IPoint (xCoordinate: Integer; yCoordinate: Integer); ... end;

implementation procedure TPoint.IPoint (xCoordinate: Integer; yCoordinate: Integer); begin self.fxCoordinate := xCoordinate; self.fyCoordinate := yCoordinate end;

type TTriangle = object ... procedure ITriangle (point1: TPoint; point2: TPoint; point3: TPoint); function Area: Real; end;

implementation procedure TTriangle.ITriangle (point1: TPoint; point2: TPoint; point3: TPoint); begin fPoint1 := point1; fPoint2 := point2; fPoint3 := point3; end;

Now you can show the main program:

Page 8: The anguish of the programming teacher on the verge of becoming object-oriented

program Points1; ... var p1: TPoint; p2: TPoint; p3: TPoint; t: TTriangle;

x, y: Integer;

begin write('point 1: '); readln(x, y); New(p1); p1.IPoint(x, y);

write('point 2: '); readln(x, y); New(p2); p2.IPoint(x, y);

write('ppoint 3: '); readln(x, y); New(p3); p3.IPoint(x, y);

New(t); t.ITriangle(p1, p2, p3); writeln('Area = ', t.Area : 6 : 2); end.

The problem of the triangle gives us such a handsome solution that we cannot avoid using it to explain inheritance: after all, isn’t a triangle just a case of a polygon, just as an orange is a case of a fruit, and a plane a case of a means of transportation? Then your troubles worsen: how are you going to define the class TPolygon? Either you put the vertices and the operations in it, or you make it an abstract class, i.e., one that does have objects but is only used to pass function-ality to its descendants. Remember that you are only starting, and you need to look serious about objects. A triangle is an array of three points, a quadrilateral is an array of four points, a pentagon is an array of five points. But you cannot say that a polygon is an array of an arbitrary number of points (you can say it, but you cannot program it in Pascal) and you cannot cheat now and say that a polygon is a list of points, because lists came after pointers in your course (and pointers come after objects). So, you must compromise and program TPolygon as an abstract class. Methods are IPolygon, Perimeter, NumberOfSides, for instance. This is less than satisfactory, because you cannot use polygons as such in your pro-gram, and this is hard to comprehend (and hard to teach). For example: if you collect an

unknown number of points from a source, to make a polygon you would like to have a method like this, taking advantage of confor-mant array schemas in Pascal (something that my implementation of Object Pascal lacks): procedure IPolygonWithPoints (somePoints: array[lb..ub:Integer] of Point);

Moreover, finding the perimeter is the same for all polygons. It should be programmed at the higher class, and then inherited by its descendants. However, if TPolygon has no data, this cannot be done. We have to program everything for each descendant. At this point, you wish C++ was more student-friendly. In C++, you can dynamically allocate vectors of an arbitrary dimension (but you need pointers, of course). For example: class point { private: double xx; double yy; public: point(void); point(double, double); double dist_to(point); };

double sqr(double x) { return x * x; }

point::point(void) { xx = 0.0; yy = 0.0; }

point::point(double x, double y) { xx = x; yy = y; }

double point::dist_to(point p) { return sqrt(sqr(this->xx - p.xx) + sqr(this->yy - p.yy)); }

class polygon { private: int np; // number of sides point *pp; // pointer to points public: polygon(void); polygon(int); point& operator[](int); double perimeter(void); int n_sides(void); };

Page 9: The anguish of the programming teacher on the verge of becoming object-oriented

That fascinating operator [] allows us to re-trieve the points in a polygon by subscripting: polygon::polygon(void) {};

polygon::polygon(int n) { np = n; pp = new point[n]; }

point& polygon::operator[](int i) { return pp[i]; }

double polygon::perimeter(void) { int i; double s = 0; for (i = 0; i < np; i++) s += pp[i].dist_to(pp[(i+1)%np]); return s; }

int polygon::n_sides(void) { return np; }

A triangle in C++ would be a polygon created with the fixed size of 3: class triangle: public polygon { public: triangle(void); triangle(point, point, point); double area(void); };

triangle::triangle(void): polygon(3) {};

triangle:: triangle(point p1, point p2, point p3): polygon(3) { operator[](0) = p1; operator[](1) = p2; operator[](2) = p3; }

double triangle::area(void) { double side1 = operator[](0).dist_to(operator[](1)); double side2 = operator[](1).dist_to(operator[](2)); double side3 = operator[](2).dist_to(operator[](0)); double semip = (side1+side2+side3) / 2; return sqrt(semip * (semip-side1) * (semip-side2) * (semip-side3)); }

Even if this works, it is somewhat surprising. Usually, derived classes have more fields and

more methods than the base class. Here, trian-gle would not need to have a field np, nor the method n_sides. Inversely, it's the polygon that needs that information, besides what trian-gle already has. But would we say that polygon is a subclass of triangle? Besides, if you create a polygon with three sides, will that polygon realize it is a triangle, and then be able to use triangles' methods? No. A triangle must be declared as a triangle. By now, you have proven the importance and usefulness of objects. (Have you?) All that re-mains is a final touch of polymorphism. The standard examples need container objects, ob-jects made for holding other objects. In a con-tainer object for objects of a given class you can place objects of that class and of any class that descends from that class. What kind of containers do we have at this point? We have the most useful of all: the array. Well, in Pascal the array is a type constructor, not an object, but that technical detail must not hinder us in out pursuit of clarity. Students who have appreciated the benefits of genericity, even with its shortcomings in a non-generic language such as Pascal (also in a non-object language as Ada, although they ignore it), will anticipate that objects are the answer. You start with a class Object as general as possible, you define a class ArrayOfObjects, the data part will be an array of Objects (forget the dimension) plus an integer for the number of elements, you pro-gram methods for finding the maximum, for searching, for sorting, and that's it. For any given array object, you only have to call the method you need. This is not polymorphism at work, though. An array of objects means that anything, anything, can go into it. At position 1 we can have an Integer (assuming integers are objects, some-thing hard to deny, although not completely true), at position 2, you can have a Char, at position 3, an object Person (perhaps from our Formula 1 problem). One can hardly see the usefulness of this, but it looks interesting. It looks interesting but it does not work, be-cause of that dimension hitch; you will solve it

Page 10: The anguish of the programming teacher on the verge of becoming object-oriented

only by dynamic allocation. You can try to salvage the situation with C++. After all, C++ has templates to handle genericity, and dynamic allocation in a case like this can be explained easily. But then you have to deal with pointers to functions, and that is beyond what is acceptable at this stage. Would your Pascal students be ready for something like this: template <class T> class Vector { private: T* v; int dim; public: Vector(int); T& operator[](int); int size(void); void sort(int, int (*)(T, T)); };

template <class T> Vector<T>::Vector(int n) { v = new T [dim = n]; }

template <class T> T& Vector<T>::operator[](int i) { return v[i]; }

template <class T> int Vector<T>::size(void) { return dim; }

template <class T> void Vector<T>:: sort(int n, int lessthan(T, T)) { int i; int j; T temp; for (i = 0; i < n-1; i++) for (j = n-1; i < j; j--) if (!lessthan(v[j-1], v[j])) { temp = v[j-1]; v[j-1] = v[j]; v[j] = temp; } }

Some would even argue that this class is not object-oriented enough. If T represents a class, the order relation should be a method in T, not a standard function. We have already seen with the method DistanceTo that binary functions look awkward as methods. But should the class T have methods for all possible orderings? Or should it have a functional slot in the data part to which you

assign the current ordering? Or should this slot belong to the array, which is the structure that is going to be sorted, after all? What are we trying to accomplish? We are only trying to program a class embodying this simple idea: to have a generic array in which to perform, once and for all, those common operations of finding the maximum, searching, sorting, which we know are independent of the type of the elements. Have we approached this goal? Hardly. Perhaps we would better skip this discussion in class (I mean, with the students). The next problem, the Formula 1 problem, is a common business oriented problem that must have a common object-oriented solution. If it has not, no one will. What objects do we have here? This question can lead to a fine lecture on how to find objects. Happily, we have plenty of candidate objects: drivers, cars, races, numbers, rankings, even programming objects such as files. If we already are champions of reuse we can immediately perceive room for generalization: drivers are persons, cars are means of transportation, races are sports competitions. Could we generalize our solution up to a program that would handle soccer championships, sailboat races, chess tournaments, in a generic way, and that would then only require the appropriate class instan-tiations? We can avoid a definitive answer, with the standard excuse: it is not practical yet. So, let us consider our objects. What is a driver object? Something that has a name, drives a car, collects points (we omit irrelevant detail, such as nationality, height, city where he lives): type DriverName = string[31]; TDriver = object fName: DriverName; fCar: TCar; procedure IDriver (theName: DriverName); function Name: DriverName; ... end;

What is a car object? (In principle, the defini-tion of TCar will go before the other, because

Page 11: The anguish of the programming teacher on the verge of becoming object-oriented

the other uses it.) A car is an object that has a number and is driven by a driver. (Again, we omit irrelevant detail, such as the make of the car, the maximum speed, the type of the en-gine, dropping completeness and forbidding reuse): type TCar = object fNumber: Integer; fDriver: TDriver; procedure ICar (theNUmber: Integer); function Number: Integer; ... end;

We run into trouble again: each object contains the other object. This cannot be programmed without resorting to some advanced strategies. Alternatively, we either drop the car from the driver, or the driver from the car. Or both. And then we introduce a new object TRacingPair handling man plus machine. type TDriver = object fName: DriverName; ... end;

type TCar = object fNumber: Integer; ... end;

type TRacingPair = object fDriver: TDriver; fCar: TCar; ... end;

This class TRacingPair is abstract (it belongs to the solution, not to the problem) but it is not an abstract class. What do we do with these objects? We read them from files, load them into arrays, we search the array of cars to validate the user in-puts, we search the array of racing pairs to get the name of the driver for a given car. As a matter of fact, we do not need the array of racing pairs. Its job is done implicitly by the two arrays, the array of cars and the array of drivers, which are loaded in parallel. So, even at the risk of compromising reuse once again, we drop the class TRacingPair. The standing array will be an array of rank records. Each rank record is an object that has

a driver and the number of points collected so far by that driver: type TRank = object(TArrayable) fDriver: TDriver; fPoints: Integer; procedure IRank (theDriver: TDriver); procedure AddPoints (numberOfPoints: Integer); function Driver: TDriver; function Points: Integer; end;

Perhaps we should announce at this stage that the field fDriver is a pointer… The array of rank records will have to be searched for a driver with a given name and sorted by points. We need three arrays; some have to be searched, some have to be searched and sorted. All have the same dimension (the number of drivers in the championship). This allows us to design a hierarchy of array classes, even in Object Pascal. We start by defining the abstract class TArrayable, of objects than can go into arrays: type TArrayable = object(TObject) end;

This class is a direct descendant of TObject, which is the standard top of the class hierarchy in our implementation. Next comes the class TArray. For simplicity, we can only add elements at the end of the ar-ray, with the method Extend, and we can in-spect them anywhere, with the method Entry: const maxDrivers = 40;

type TArray = object fElements: array[1..maxDrivers] of TArrayable; fNumberOfElements: Integer; procedure IArray; function Entry (atThePosition: Integer): TArrayable; procedure Extend (withElement: TArrayable); function NumberOfElements: Integer; end;

A searchable array is an array that can be searched for a good element:

Page 12: The anguish of the programming teacher on the verge of becoming object-oriented

type TSearchableArray = object(TArray) function First (function IsGood (theElement: TArrayable): Boolean): Integer; end;

A sortable array is an array that can be sorted for any parametric order relation: type TSortableArray = object(TSearchableArray) procedure Sort (function BetterThan (left, right: TArrayable): Boolean); end;

The implementation of these methods is straightforward. The only one that you cannot explain is the method Extend. procedure TArray.Extend (withElement: TArrayable); begin fNumberOfElements := succ(fNumberOfElements); fElements[fNumberOfElements] := TArrayable(withElement.Clone); end;

The method Clone comes from the class TObject; it makes a duplicate copy of the ob-ject and returns a pointer to it. The pointer to the copy is stored in the array. The typecast TArrayable(…) is necessary because the method Clone returns a TObject, and an object of a higher class cannot be assigned to one of a lower class. By now, we have built the object infrastructure that we need: classes TCar, TDriver, TRank, TArrayable, TArray, TSearchebleArray, TSortableArray. We need three arrays in the main program: var drivers: TSearchableArray; cars: TSearchableArray; rank: TSortableArray;

The variable drivers will be an array of TDriver, but, due to polymorphism this is not declared. A similar comment applies to the other vectors. How do we load these arrays? We do not have methods for reading TDrivers, TCars or TRanks. Should we create an intermediate class TReadable to encompass this capability,

make it an ancestor of TArrayable, and then override the method in each class? Actually, do we have objects in our files? The racers file is simultaneously the file of cars, the file of drivers and the file of race pairs. Should the method for reading a driver know that it must skip some information in each line? Is this a symptom that the problem did not have an object-oriented analysis? If it had, would there be three different files? Suppose we decide to program a method for reading a TDriver: type TDriver = object(TArrayable) ... procedure Read(var fromTheFile: Text); end;

This method changes the state of the argument, and that is not forbidden. But is this object-oriented programming? Does this method really belong here in the TDriver class, or does it belong to a yet to be created class for files? This would be a class for text files of TArrayable objects, and the method for reading would be a function: type TFile = object ... function Read: TArrayable; end;

If we follow this trail, we will now need three subclasses of TFile, and in each of them we override the method Read. Let us suspend our discussion here. Our goal was not to show object-oriented solutions for our introductory problems, but to discover the kinds of difficulties we can expect to face when introducing objects at an early stage in programming courses. It appears that there are two classes of difficul-ties. First, Object Pascal and C++ are not very helpful. Object Pascal is simple, but it becomes complicated very quickly, because we have to be constantly aware that objects are pointers. We cannot pretend for too long that objects are just records with methods. Besides, some familiar objects in pro-gramming are not objects. The type Integer is just a type, not a class. Therefore, if we need

Page 13: The anguish of the programming teacher on the verge of becoming object-oriented

a TArray of integers, we must first create a class TInteger, descendant of TArrayable, and this seems very unnatural. Furthermore, Object Pascal lacks proper encapsulation and this goes against the intuitive use for objects. The second class of difficulties come from the absence of an object methodology, when we introduce objects. Object programming seems to absolutely require a methodological approach (perhaps starting in analysis), in order to be effective. But we do not want to have to give a course on object-oriented methodologies before students know and feel what an object is. We face the classical chicken and egg problem: objects need methodology and object methodology only makes sense if we already have objects. Does this mean that, after all, object-oriented programming is an advanced technique? Absolutely not. It only means that I do not know enough of it. Should I refrain from teaching it until I have answers to my hesita-tions? No. The best way to learn is by teaching. Should I postpone objects until the Pascal for object-oriented programming arrives? Of course not. There is plenty that can be done with Object Pascal (although this is not the Pascal for object-oriented programming).

6. The future (conclusion) Notwithstanding, the future is bright. For many, objects were a new vein in a gold mine that was running out of gold. Consultants found a new ground where they cannot be wrong, because nobody knows what is right. Professional trainers were delighted to offer a new line of courses to an army of programmers who promised to themselves that this time they would not stay behind. Methodologists spread like mushrooms announcing the “definitive” method. (Now we know why the solution for our problem is software was not found before: there were not enough objects.) Compiler writers were able to postpone their layoff, pushing forward with the nth plus 1 version of the compiler. And book writers, like myself, rushed to their

computers to write the sequels with objects to their hit books. Therefore, there is no reason why this most favorable state of affairs shouldn't benefit you, the programming teacher, as well. It can benefit you first because you draw pro-fessional satisfaction from learning to do things in a new, fascinating way. (Isn't it one of the joys of programming that we are learning all the time?) Then you will be pleased to pass your thoughts to the students, at a moment when they are still fresh. The discussion can be much more stimulating than, say, when you were teaching the basics of structured programming, which is already a part of you. As a side effect, it is likely that your colleagues will look at you with more respect. For many, teaching programming is a kindergarten activity. The true technological subjects are Artificial Intelligence, Operating Systems, Data Bases, ... But these all are becoming object-oriented too, and your colleagues have to recognize that only see part of the picture. They turn to you for help, and expect you to prepare students in the modern way they now need. After all, when inheritance and polymorphism are involved, programming has to be for adults only. Some people seem to believe in the future, with objects, all the software troubles will be a memory of a colorful, rustic past. Developing software will be easy at last. With powerful tools, powerful environments, powerful meth-odologies and powerful computers, powerful programmers will not be necessary anymore. I have a problem with these arguments, because I made a vow never to use the words “easy” and “powerful”. In programming nothing is easy. To say that something is easy is just a metaphor indicating that you should pay double attention. And powerful means that if you do not watch out you are going to be run over by it. What is fascinating about the future is that it always fools you. You predict x and y happens instead. With so many people trying to peek forward, somebody is bound to guess right, in

Page 14: The anguish of the programming teacher on the verge of becoming object-oriented

spite of himself. Should we teach object tech-nology now because according to the propa-ganda in the year 2003 everybody will want it, or simply because today it helps us do a better job in programming?

Reference [McCracken 65] Daniel D. McCracken, A

guide to FORTRAN IV Programming, John Wiley & Sons, Inc., New York, 1965.