A Principled Approach to Teaching OO First David Gries Computer Science, Cornell University Ithaca, NY 14853 (607) 255-0393
[email protected] that violations of these principles contribute to the current state of affairs in teaching programming —OO based or not.
ABSTRACT There has been debate about whether OO should, or even can, be taught first in CS1 (using Java). We claim that OO can be taught successfully, provided certain principles are followed. These principles lead to the requirement of an appropriate model for classes and objects, which we provide.
A key contribution of this paper is a model for objects and classes that (1) rises above the computer, (2) uses an analogy to which students can relate, and, based on principles, (3) properly gives each object a name. The technical material in this paper was described in [15], but we have not had the opportunity to present it to the wider SIGCSE audience. Also, this presentation, based on principles, provides more justification for our approach to teaching than given in [15].
Categories and Subject Descriptors K.3.2 [Computer and Information Science Education]: Teaching object-oriented programming. D.1.5 [Programming Techniques]: Object-oriented programming.
2. PEDAGOGICAL PRINCIPLES
General Terms
We turn your attention to Michael Caspersen’s PhD thesis [11]. This thesis presents research and conclusions on the teaching of programming that is based on sound theories of pedagogy and cognition as well as experience. It deals with teaching OO, but its findings are applicable in more general domains. We have not seen a better study on this topic.
Documentation, Human Factors, Languages.
Keywords CS1, objects first, teaching OO, teaching object-oriented programming.
Among other things, Caspersen discusses two important principles concerning teaching novices, which happen to form the basis of our own teaching of programming.
1. INTRODUCTION There has been much debate on the topic of teaching OO first when teaching programming using Java. A SIGCSE debate on the issue [1] was preceded and followed by email on the SICGSE mailing list, and Kim Bruce wrote a summary of the discussion [7]. A list of references on “OO first” is given in [17]; in fact, this extensive debate [17] deserves to be read by everyone involved in teaching OO.
Principle 1: Reveal the programming process, in order to ease and promote the learning of programming. Principle 2: Teach skills, and not just knowledge, in order to promote the learning of programming. Teaching programming skills cannot be done in an isolated lecture or two. Of course, there will be lectures on stepwise refinement (or stepwise improvement, acc. to Caspersen), loop invariants, OO design, etc. But discussions of programming skills should be woven into almost every lecture —e.g. when the teacher develops the spec of a method before the method body, discusses where local variables should be declared, writes a class invariant, and develops a suite of test cases in a JUnit class. Imparting skill, as well as transferring knowledge, should be our aim.
Rather than describe what others have said on the topic, in the time and space available, we give our views on how to teach OO. We give some principles on which we believe teaching programming should be based, and we give examples from texts1 to show
1
Throughout, by “text”, we mean “introductory programming text”. Quotes from texts are representative of many texts and are given without citation. The purpose is not to point out individuals but to show the state of affairs.
In our opinion, few texts treat programming skills appropriately. They treat programs, not programming. They focus largely on knowledge, not skill. In a sense, the field of formal programming methodology has failed. Throughout the 1970’s and 1980’s, research helped us learn how to teach programming skills, often in an informal manner but based on a formal theory of programming. The field has not embraced the idea, to say the least. It is a tragedy that most students in CS graduate without ever having heard the term loop invariant, much less having used it.
Permission to make digital or hard copies of all or part of this work for personal or classroom use is granted without fee provided that copies are not made or distributed for profit or commercial advantage and that copies bear this notice and the full citation on the first page. To copy otherwise, or republish, to post on servers or to redistribute to lists, requires prior specific permission and/or a fee. SIGCSE’08, March 12–15, 2008, Portland, Oregon, USA. Copyright 2008 ACM 978-1-59593-947-0/08/0003...$5.00.
Lately, we have realized that making two changes to our normal mode of doing business helps with principles 1 and 2.
31
machine and should not be confused with the variables that might refer to that object.”
First, for the first assignment or two, allow students to resubmit it several times until they get it right —i.e. require mastery. Write a method specification or class invariant incorrectly? Correct and resubmit. Inadequate test cases? Develop more, test, and resubmit. Error in the program? Debug, fix, and resubmit.
A model for classes and objects is needed that rises above the computer and that is based on an analogy to which students can relate. We introduce such a model in Sec. 3.
In this way, instead of getting penalized for misunderstandings and mistakes in this entirely new subject of programming, students learn from them. Also, students with prior experience have a chance to mend their bad habits without being penalized. Everyone feels better about the course.
We are not alone in believing that a programming language definition should be computer independent. We quote from the definition of Algol 60 [2]: “The purpose of the algorithmic language is to describe computational processes. …
Second, early in the course, give each student a one-on-one session with the instructor, a TA, or a trained senior “consultant”. In the session, present the student with a class to develop and give them feedback as they develop and debug it. Give hints on typing, on compiling often, on writing method specifications before method bodies, on developing test cases —on anything that arises during the session that will help the student learn about programming and gain confidence in their ability.
A variable is a designation given to a single value. Assignment statements serve for assigning the value of an expression to one or several variables …. The process will … be understood to take place in three steps as follows: 4.2.3.1. Any subscript expressions occurring in the left part variables are evaluated in sequence from left to right. 4.2.3.2. The expression of the statement is evaluated.
Such a session can give the tentative, confused beginning students some confidence. “Experienced” students can be helped too.
4.2.3.3. The value of the expression is assigned to all the left part variables, with any subscript expressions having values as evaluated in step 4.2.3.1.”
Principle 3: Present concepts at the appropriate level of abstraction.
The computer is not mentioned in describing either the purpose of the language or the semantics of any statement.
We all believe that abstraction is important in CS. It is discussed everywhere. Burg and Thomas [8] call abstraction “arguably the most fundamental intellectual activity in the field of CS.” Gunter Gorz [16] discusses abstraction as a fundamental concept in teaching. One text says that, “a good abstraction hides the right details at the right time so that we can manage complexity.”
Principle 4: Order material so as to minimize the introduction of terms or topics without explanation: as much as possible, define a term when you first introduce it. This seemingly obvious principle is difficult to follow when teaching Java, and we cannot claim to adhere completely to it. We do believe that the principle almost forces one to teach OO first, because almost every line of a program deals with a class or object. But even when teaching OO first, this principle is difficult to follow. In some cases, a “spiral” approach is needed. For example, one can introduce methods in a way that allows the student to start writing methods whose bodies are method calls or returns and, later, explain methods in depth.
Kim Bruce’s lecture [6] on the occasion of his ACM education award was about using abstractions to make concepts concrete. Finally, the report Computing as a discipline [10], which we coauthored, discussed the three major paradigms, or cultural styles, used in CS: theory, abstraction (modeling), and design. But many programming texts fail to use abstraction appropriately, e.g. by describing variables and assignment in terms of computers:
Teaching Java using either applications or applets violently violates Principle 4. Applications require knowledge of keyword static, methods, parameters, String arrays, etc., while applets require knowledge of subclasses, inheritance, and more.
“A variable is a name for a memory location used to hold a value of some particular data type.” “When [the assignment statement is] executed, the expression is evaluated … and the result is stored in the memory location ….”
The way out is to use an IDE that allows any expression/statement to be evaluated/executed immediately, without requiring an application or applet. What a freeing experience! It changes drastically what, when, and how we teach. Every lecture can demo some aspect of Java or of programming methodology using the IDE. We develop programs in stepwise fashion in class, alternating between development and testing. Our students learn about applications and applets near the end of the course.
“The computer must always know the type of value to be stored in the memory location associated with a variable.” “An object reference variable actually stores the address where the object is stored in memory.” This computer-centric view gives the impression that only a computer can execute a program, which is wrong. Students should realize that they, too, will have to execute sequences of Java statements from time to time, e.g. for purposes of debugging.
DrJava [12] was the first IDE for Java to provide the ability to evaluate/execute any expression/statement. BlueJ [3] has added a command window that gives the same facility.
Further, introducing computing concepts in terms of the computer can create unnecessary and confusing detail, especially when OO concepts are described in terms of a computer, with discussions of pointers to objects in memory, heaps, and other implementationrelated terms. For example consider this quote:
Principle 5. Use unambiguous, clear, and precise terminology. Here is terminology that doesn’t work. Pointer and reference. Students do not know what a pointer is. Even after you explain, they still have difficulty understanding what an assignment statement b= c; means when c contains a pointer. With appropriate abstraction away from the computer, these terms become unnecessary.
“An object has its own unique identity, which distinguishes it from all other objects in the computer’s memory …. An object’s identity is handled behind the scenes by the Java virtual
32
here. The name of the class in the upper right part of the object indicates what file drawer it belongs in.
Inheritance. In our opinion, the definition of Java makes a big mistake in its use of this term: private variables are not inherited, even though they appear in every object of the subclass! According to the Java definition, only ones that are directly accessible are inherited.
Instance variables and methods are placed in the object. When drawing a variable, its type is optional. For methods, we draw only their signatures, although at times, to illustrate a point, we place the whole method in the object. The position of the components in the object has no meaning at all.
We prefer to use the term as it is used in English. A child may inherit a million dollars, but the terms of the inheritance may prohibit full access to the money until age 21. Similarly, all fields and methods are inherited —they appear in every object of a subclass. Whether they can be referenced directly is an orthogonal issue.
The inclusion of fields in a manila folder (or object) is natural. We explain the inclusion of the methods as follows. In a dentist office, each employee knows how to carry out some tasks —the secretary creates folders and inserts patients’ names and addresses, the nurse makes entries on a diagram of the teeth, the accountant deals with bills and deposits. Placing the instructions in each folder, written as methods, allows anyone to carry out any task, providing more flexibility.
Formal and actual parameter. These unfortunate terms, introduced in Algol 60, should be recalled. Most texts tend to drop the adjective, resulting in ambiguity and confusion. Far better is parameter and argument —two totally different words for two totally different concepts.
Principle 6, below, comes from [13]. The context there was different, and the principle was not worded in such a general fashion.
In summary, utmost clarity of terminology is necessary, for the choice of terminology can influence how easy or hard it is for students to grasp the concepts.
Principle 6. Introduce names for entities under consideration.
There are other principles to be followed in teaching programming, but these will give you an idea of our general philosophy. We now turn to a consideration of teaching objects first.
In OO, we constantly refer to objects, usually talking about “pointers” to them. Following principle 6, we explicitly provide a name for each object, which appears on the tab of the folderobject. In the object written above, the name is a0.
3. THE OO MODEL OF EXECUTION
The name is chosen by whoever creates (draws) the object. The only rule used in creating it is that different objects have different names. If the computer creates an object, we have no say in what name is chosen, much like we have no say in the address given to a house or the social security number given to a person. If we create-draw an object, we get to choose its name.
Principal 3 concerns presenting concepts at the right level of abstraction. This means (at least) presenting a model of execution of a program that is not tied to the computer. du Boulay et al [4, 5] separate the difficulties that novices have in learning to program into five areas. One of these has to do with the runtime model of programs. This model has to be at the right level of detail, using enough abstraction to hide unnecessary details and provide the right perspective, while still remaining concrete enough to make sense to the novice. Caspersen [11, Sec. 10.3.1] also discusses the need for a “notional machine”.
The class name, C, acts like a type. The values of the type are the names of objects of the class —the names on the manila folders of class C. To the right are two variables, both containing the name of object a0. This makes sense, in the following way. Suppose we are modeling a dentist office and the folders are patient’s records. Both the secretary, John, and the accountant, Mary, have access to the folder, and they access it looking for folder a0 in file drawer C.
Two major aspects of most programming languages are: •
The structural/organizational aspect, and
•
The algorithmic/procedural aspect.
Back in the good old days, the first aspect was essentially ignored, because the main feature for organization was the subroutine, (procedure or function). The structure was rather flat. Want more functionality? Add more subroutines. Over the years, various kinds of modules were developed to provide more structure, but OO has been the most successful structuring mechanism yet.
Do not underestimate the importance of this model of classes and objects, especially the name on the tab of the object, for the model has several advantages: 1.
A huge problem with many current texts is that they provide no consistent pictorial presentation of objects. The pictorial nature of our objects makes the concept concrete. Students can see what an object is. We draw objects often, and we force our students to draw them.
2.
The inclusion of methods (as well as fields) in an object is important for later understanding of how the body of a method can reference a field of the class, as we will see later.
3.
The terms pointer and reference are not used. Instead, we have a new type, the names on the tabs of objects. Automatically, one understands that an assignment statement like
When teaching OO first, it is important to discuss these two aspects and make clear that the structural aspect will be studied first. We now present a workable OO model. In our model, a class is a file drawer of a file cabinet, and the manila folders in the cabinet are the objects of the class. The class definition describes the contents of each manila folder (object). When first introducing the model to students, we bring actual manila folders, filled with pieces of paper giving the fields and methods of the object.
John= Mary; places in variable John a copy of the name in variable Mary.
After a few weeks, we forget about manila folders and talk only in terms of objects, but we continue to draw objects as shown
We do not use UML diagrams for objects because they have no place for the name of the object (the name on the tab of the
33
it, search outward through enclosing constructs until the declaration of v is found: Look first in the block in which the assignment appears, then in successive surrounding blocks. If not found, look in the surrounding context, which is object a0 itself. If it is not there, look in the surrounding context, which is the file drawer.
folder) and this name is a necessary part of the object. It is this name that leads to easier understanding. In fact, some of the UML tutorials on the web are misleading. Consider the UML diagram for class Counter, to the right. The class definition declares a field state and three methods. One tutorial suggests drawing an object of this class as shown to the right. Variable theCnt contains the “pointer” to the object, but the diagram gives the mistaken impression that the variable contains the object.
This general inside-out rule is used, perhaps with some restrictions and changes, in every programming language, as well as logic, and it is reasonable to show students this general rule. Our model for classes and objects has other advantages, e.g. in explaining inner classes, anonymous classes, and the process the Java compiler goes through in flattening the class structure. We don’t have space to go into this here. See [14, 15]. Some people oppose the idea of presenting a class as a file drawer, with the class definition defining the contents of all manila folders (objects) in the file drawer. A class is not a file drawer, they say. One doesn’t have to use this analogy.
The BlueJ [3] model for describing objects makes the same mistake, in that the variable that contains the name of an object is tied too closely to the object and there is no way to store the name of the object in another variable.
But it is important to draw objects with: (1) the name of the object appearing explicitly in the object, (2) a partition for the class and for each superclass, and (3) the fields and the methods residing in the appropriate partition.
Objects of subclasses are drawn in a way that distinguishes the inherited components from the components declared in the subclass. We show how we do this.
Also useful is to have all objects and static components of a class C in one box, named C. This allows a discussion of the general inside-out rule for finding a variable or method. It also makes it easy to see why the notation C.c is used to reference a static component c of C. Inside the box, just use c; outside the box, you have to indicate where to look and thus write C.c.
To the right is an object of subclass Circle. The partition for Circle, which contains all instance components declared in Circle, is at the bottom. Partitions for superclasses are drawn above. The subclass inherits all the components defined in the superclasses, and you would see them all there if we had drawn them all; we omitted some to save space.
4. OUTLINE OF LECTURES ON OO It may help to see an appropriate order of topics and to see when algorithmic aspects enter the picture. Below, we outline the first part of our 14-week introductory programming course. The OO topics are in italics. Each week has two 50-minute lectures, with a closed lab between the two lectures. The labs reinforce what was taught in lectures and may contain new material (e.g. class ArrayList). About half the class has no prior programming experience.
The partition for class Object, the superest class of them all, is not always drawn, since we know it is always there. The format of objects is used to explain overriding using a bottom-up rule. Given a method call, search for a matching method starting at the bottom of the object and search upward.
The first five lectures focus on structure and organization, with methods that contain only method calls, returns, and, beginning in lecture 4, assignments. In total, about 7 lectures are devoted to OO, which is about 25% of the course.
The figure below shows the file drawer for a class C, with two objects. In our model, the file drawer contains also the static components —in this case, a static variable and static method.
As you can see, lectures 2-5 are purely about OO. Thereafter, material on OO is interspersed with algorithmic material, until, by lecture 11, all of OO has been introduced. Lecture 1. Types, expressions, variables, and assignment. Lecture 2. Objects as manila folders. JFrame objects are created and their methods are called using DrJava. Lecture 3. Definition of a subclass of JFrame, with a function to compute the area of a JFrame window and a procedure to make its width equal to its height. Lecture 4. Fields, getter/setter methods, JUnit testing.
We cannot overemphasize the value of these diagrams in helping students learn what an object is. Once students grasp the idea, these diagrams can be used to explain various concepts.
Lecture 5. Static variables, the class hierarchy, class Object. Lecture 6. Methods; local variables; the if-statement. Lecture 7. Inside-out rule; super; this. Start stepwise refinement.
For example, we use an inside-out rule [14, 15] to determine what references mean. Suppose an assignment v= w; appears in the body of method toString. Suppose we wish to find the declaration of variable v associated with the v in the assignment v= w; in the body of method toString in object a0 in the figure above. To find
Lecture 8. Constructors in subclasses. Stepwise refinement. Lecture 9 and 10. Recursion. Lecture 11. Casting about; instanceof.
34
Obtain our labs, assignments, power-point presentations of lectures, and more at www.cs.cornell.edu/courses/cs100j/2007sp and www.cs.cornell.edu/courses/cs100j/2007fa/.
5. CONCLUSION We believe that the principles discussed in this paper lead to the conclusion that OO first is the only way to go. But don’t go this way without paying sufficient attention to: (1) the programmingskill aspect, (2) a model of objects and classes to which students can relate, (3) notation and terminology, (4) the order in which topics are introduced, and (5) an IDE that does not require an application.
6. ACKNOWLEDGMENTS Thanks to Paul Gries, co-author of [14, 15], for all his help over the years and to Michael Caspersen for his comments on drafts of this article and his help in the past.
REFERENCES
Our model of objects and classes, which we have been using successfully for 7–8 years, is discussed in Gries and Gries [14], which was designed with teaching OO first in mind. With the text comes a CD with over 250 recorded lectures with synched animation, each 2–5 minutes long; this CD provides another alternative for students to learn the material. Further, it contains more lectures on the development of programs than one can put in a paper book, because of the static nature of paper.
[1] Astrachan, O., et. al. Resolved: objects early has failed. Debate at SIGCSE 2005. [2] Backus, J.W., et al. Revised report on the algorithmic language Algol 60. CACM 6, 1 (Jan 1963), 1–17. [3] BlueJ —The interactive Java environment. www.bluej.org. [4] du Boulay, B. Some difficulties of learning to program. In Studying the novice programmer, Hillsdale, NJ, Lawrence Erlbaum, pp. 57-73, 1989.
To judge the success of our method of teaching programming, we can give only information about our own course, which is taught to 130–160 students each semester. One stated outcome of the course is that the student will Understand OO concepts, as used in Java: classes, subclasses, inheritance, and overriding. This includes an operational model of method calls.
[5] du Boulay, B., T. O’Shea, and J. Monk, J. The black box inside the glass box: presenting computing concepts to novices. In Studying the novice programmer, Hillsdale, NJ, Lawrence Erlbaum, 1989.
One assessment tool for judging how well this outcome is met is a set of questions on the course final that require tasks like writing parts of a class, explaining evaluation of a new-expression, drawing an object, writing an equals function, giving definitions, executing a sequence of instructions that include creation of new objects and aliasing, and so on. Students do well on such questions —having had practice on midterm tests and on programming assignments— averaging between 75% and 85% on them.
[6] Bruce. K. Using abstractions to make concepts concrete. SIGCSE ’05 (23 Feb 2005), St. Louis, Missouri.
This direct assessment tool is backed up by a question on the course survey, completed by 95% of the students. Almost all the students said that they understood classes and objects “fairly well, or very well, or have a complete picture.” A few students said they had a good conceptual understanding but had difficulty putting them into practice. Only 5/150 students still had difficulty.
[9] Colburn, T., and Gary Shute. Abstraction in computer science. Minds and Machines 17, 2 (July 2007), 169-184.
[7] Bruce, K. Controversy on how to teach CS1: A discussion on the SIGCSE-members mailing list. Inroads (Dec 2004). [8] Burg, J., and S. Thomas. Computer science: from abstraction to invention. www.cs.wfu.edu/~burg/ papers/AbstractionTo Invention.pdf.
[10] Denning, P., et al. Computing as a discipline. CACM 22, 2 (Feb 1989), 63-70. [11] Caspersen, M.E. Educating Novices in the Skills of Programming. DAIMI PhD Dissertation PD-07-4, Computer Science, University of Aarhus, Denmark, May 2007.
Many students voluntarily stated that the analogy in terms of file drawers and manila folders was very helpful, but a very few, 3–4, were totally against it. Here are examples of comments:
[12] DrJava. http://www.drjava.org/ [13] Gries, D. The Science of Programming. Springer, NY. 1981.
“The manila folder analogy was very clear to me. I have never programmed or even seen Java before and with your analogy it was very clear and easy to understand.”
[14] Gries, D., and P. Gries. A Multimedia Approach to Teaching Progamming, using Java. Springer Verlag, 2005. [15] ___. Frames and folders: a teachable memory model for Java. J. Comput. Small Coll. 17, 6 (May. 2002), 182-196.
“I took AP Java when I was 16 and I thought I knew it then, but this class definitely made me understand classes and objects more if not completely.”
[16] Gunther, Gortz. Abstraction as a fundamental concept in teaching computer science. www8.informatik.unierlangen.de/ IMMD8/staff/Goerz/rennesa.ps.gz.
“Scrap the metaphor entirely. It does the student no good in trying to learn the structure of java. If I did not understand classes and objects in java before I would be completely lost.”
[17] Lister, R., et al. Research perspectives on the objects-early debate. http://portal.acm.org/citation.cfm?id=1189136.1189183.
35