Python!
16 Dec 2024
a not entirely fictional conversation
Changed in version 1.0: Fri Dec 13 18:26:38 EST 2024: initial release
1 Design First
Hi. I new here and looking at our introductory programming curriculum. Shouldn’t we be teaching Python? I am not sure why we teach Racket to novices? | We don’t teach Racket. |
But that’s what everyone says. | Only people who have never attended a properly taught Fundamentals I. We actually teach design principles. |
What does it mean to teach design principles? | Imagine someone who hasn’t programmed before. Confront this person with a word problem and a blank screen. How should this student proceed? How should an instructor check whether the person is making progress toward a solution? |
I guess this is one way of thinking about a first course. | Teaching students to proceed systematically helps them and helps instructors help students. |
What does “systematic” mean? | We think of the most basic program as just a function from some input to some output, a box with an arrow going in and an arrow coming out. |
Put this way, programming is the task of putting text into this box. | Exactly. But we want to help students write this text in a step-wise fashion. |
Do these steps result in products? | They do. Each step should add something that give students a sense of getting closer to the solution. |
Okay. | And an instructor can inspect these products to diagnose a student’s work. |
Can you make an example? | Let’s start with the input arrow. Would you consider it natural to figure out exactly what kind of inputs go into the program? |
It sounds like the only way to make sense of how the output should be computed. | You got it. So a student should write down exactly what the inputs are and, because people need to be concrete, a student should make up examples. |
I am with you. A student could even make examples first and then generalize the examples to get a comprehensive description of the inputs. | Yes! |
Well, this clarifies what you mean by “a teacher can check the product of a step.” | Studying inputs is only the first step. |
How about a second example of a design step? | Obviously, students should work out examples of how the “box” can determine outputs from the concrete input examples. |
Is this related to test-driven programming? | Only loosely. We consider it natural that solving general problems requires “working through examples,” which we use as a slogan. |
Doesn’t this step naturally lead to tests? | Of course. You’re getting the hang of it. Each step builds on the products of the preceding steps. Examples become unit tests. |
This sounds really cool. | It is and experience shows that it works really well. And there is more. |
Like what? | A program isn’t just a simple function from inputs to outputs. |
How come? | Most programs are a composition of several functions. |
So there is more than the basic design recipe? | Students must learn to distinguish between atomic functions, which perform actual work, and function that compose others because they need to perform several tasks. |
Is the distinction always obvious? | Wouldn’t you agree that students must learn to recognize when a program performs several tasks and break it down into a series of “smaller’ programs? |
This is a standard goal of Programming 101. | One of the early steps is the formulation of a purpose statement. |
Do you mean the students must articulate the purpose of a program in their own words? | Yes. And if this statement mentions more than one task, the student should design a composite function and make a list of wishes with one entry per task. |
Even I can see how such methods and functions become incomprehensible. | Precisely. Identifying and naming each computational task makes for short and comprehensible programs. |
But are programs really functions from inputs to outputs? When I use apps on my phone, I swipe left and right; I use the keyboard to enter text; I even speak with my apps. | You describe forms of inputs and outputs. Why should such programs not be functions? |
I just don’t see it. | These inputs are forms of information. Your phone’s operating system turns them into input data and hands them to your program. For example, if you hit “E” on the keyboard, the app may receive a struct: (key-stroke "e" UpperCase). Even sound-based information becomes data for your app, in whatever language it is written. |
Then how does my phone’s web browser show pictures? | Easy. Your browser app hands data to your phone’s operating system that tells it which pixels on the display to paint in which color. (Programmers often use react.js for these things.) |
I get the idea. But how can teaching design steps take a whole semester? | Because there are so many different ways of encoding information as data in a programming language. |
Do the design steps differ for different forms of data? | Kind of. As the descriptions of input data becomes more and more complex, the design steps can provide more and more help. |
Why? | When the data is simple, the knowledge of how to work through examples comes from the app’s domain. As data becomes complex, computer science provides guidance to deal with structure. |
Interesting. Can you give me an example? | What’s a file? It’s a long sequence of “things.” Think of a family tree, say, the tree of all parents, grandparents, great-grandparents, and so on. |
Whew. Do you teach students how to look for genetic markers in such a family tree? | Kind of. We keep the domain of application simple so that novices don’t get scared because they think DNA biology is needed to understand program design. |
Do students also learn to cope with a tree of all descendants? | Absolutely. |
You mean first-semester students deal with tree-shaped data? | Yes, and graphs. |
Wow. This sounds like they are getting started on algorithms. | In a sense, but we also make it fun. |
How? | We have them create interactive graphical programs and even components of distributed programs. |
I can’t see first-semester students create distributed programs. | Students have created texting apps so they can share messages with each other. |
Texting apps?!? Wow. | In another semester, they implemented a mini version of Spotify, which allowed them to share songs and play them. |
Your students can write such complex programs in their first semester? | They write the client pieces and they understand them. |
Who writes the server? | Usually we do. But we have also had students create distributed games. Search for “hungry henry realm.” |
Thanks for this extensive explanation. But, do you have to teach Racket? | We really do not teach Racket. |
2 Language Second
What do you mean you don’t teach Racket? I have seen the code. | :-) |
The parentheses pile up everywhere! | Sure, the syntax of the language is fully parenthesized but that doesn’t mean it’s Racket. But it’s really just a prefix form of algebra. |
Meaning? | A beginning programming student needs a simple model of computation. |
Why? | Don’t you think a student should be able to figure out how a program runs? How it determines the output from the input? |
I guess. I always thought it’s just about stacks and tables of memory cells. | Really? A student should understand a call stack first and then learn to program? |
If you put it this way ... | Every student admitted to university is supposed to have remember the basics from pre-algebra. It’s covered in middle school. |
But how is pre-algebra model of computation? | A program is a function. In pre-algebra a student might see f(x) = ... x ... x .... And, in Beginning Student Language it’s just (define (f x) (... x ... x ...)). |
So? | Now let’s assume the operating system invokes f on 42. |
Okay? | In pre-algebra a student would calculate f(42) = ... 42 ... 42 .... |
I think I get it. | Yeah, in Beginning Student Language, the calculation is similarly simple: (f 42) means replace all occurrences of x with 42: (f x) = (... 42 ... 42 ...). |
Pre-algebra cannot explain all of this Beginning Student Language. | They will need a bit of algebra. Conditional functions are piecemeal-defined function. Structures are like Cartesian points. |
We cannot expect students to remember pre-algebra or algebra. | Are you saying a university might be cheating with admissions. |
No, no way. | Okay. |
If it’s this simple, why not teach Racket? | Because all off-the-shelf programming languages (from industry) suffer from serious problems that confuse beginners. |
How? | I think you may have seen C++. |
:-) | How does a compiler react to this cost_per_slice * number_of_slices = my_contribution; |
What do you mean? | This is perfectly legitimate algebraic calculation to determine a student’s share of the cost of a pizza. |
Hmph. But everybody knows that in C++ a variable assignment has a variable on the right side. | A beginner? |
It wouldn’t happen in other languages used for teaching! | Like Python? Try it. |
"SyntaxError: cannot assign to expression here. Maybe you meant ’==’ instead of ’=’?" | Do you think a beginning student understands this error message? Reacts properly to it? |
I have never observed beginning students. | I have. For years and years. |
So what’s the point? | The implementation of an industrial language assumes that the programmer knows the whole language. But beginners don’t, and beginners make mistakes. |
And? | This means error messages are formulated assuming that the programmer knows the whole language. |
I see. How does Beginning Student Language fix this? | It is designed to be as small as possible with a simple computational model. |
Does this help? | Yes, a small language’s error message are easier to understand than the ones a large one like C++ or Python or Racket deliver. |
3 Design First, 2
Then why does the second course teach Java? | It doesn’t. It also teaches design principles. |
Why do we teach design principles again? Don’t they see enough in Fundamentals 1? | Hardly. Design principles are complex, and complex topics need reinforced learning across time and instances. |
Explain. | Fundamentals 1 uses a simple programming language. Students have to see design principles in a different language. |
I thought Beginning Student Language covers it all. | It’s not typed, so students’ programs don’t get checked before they hit Run. That’s intentional. Type checking introduces yet another set of error messages. |
So the second language has to come with type checking? | Correct. |
Why not make up a Typed Beginning Student Language for the second course? | Students also need to see a language used in industry. And they should see an object-oriented one, because that’s still one of the dominant design idioms. |
Doesn’t Racket support object-oriented programming? | It does. But the more languages our students see, the better they can transfer design principles among them. |
Fair. Is object-oriented programming all about assignment statements? | Way back, Alan Kay said “to find a more flexible version of assignment, and then to try to eliminate it altogether.” And he invented object-oriented programming. |
That was written in the 1990s! | Does this make it wrong? Josh Bloch’s book is not about assignment statements either. |
Who is Josh Bloch? | The guy who wrote Java’s API and its basic libraries. His book deeply influenced Fundamentals 2. |
Really? | His book is essentially a set of design principles, and it matches what we teach in Fundamentals 1. And one thing is argues for is to avoid assignment statements as much as possible. |
Oh. | Yes, and so we try to show how to adapt the principles of Fundamentals 1 to this different language and build on them. |
Why is it necessary to build on them? | Designing software systems demands much more than designing programs. At a minimum, we need to teach our students how to collect related functionality in one container and separate it from other pieces of functionality. |
I see why we would want classes then. | And interfaces and abstract classes. |
Yes, students need to learn to program to interfaces. Why abstract classes? | Abstracting common patterns is key. It even has a name in industry: DRY. We teach the basics in Fundamentals 1 but the mechanism differs from language to language. |
That’s an interesting point. Does Bloch explain all this? | He does, even in the first edition of his book. |
I guess if one of the Java creators writes this, it’s okay. | We owe our students even more. |
More? | They need a path from simple programs to larger and large systems. Fundamentals 1 and 2 and Object-Oriented Design are the first three steps on this path. |
Do students really need to know all this to go on a co-op? | Do you want our students to outshine those from Harvard and MIT as software developer? |
That would be nice. The year of Java will do it. | We don’t teach Java. |
4 Language Second, 2
That’s what the course abstract says. We teach Java and, I assume, traditional programming in preparation of the Object-Oriented Design course and co-op. | No, we pick elements from Java needed to teach object-oriented design principles. |
It sounds like a contradiction to what you said about Beginning Student Language. | How? |
Java is a large language, and its error messages are sometimes beyond obscure. It signals syntax errors, type errors, and various run-time exceptions. I hate null-pointer exceptions. | The second semester should confront students with some of these realities. It must strike a first balance between principles and friction with reality. |
Wouldn’t you argue that we should protect our students for a bit longer? | From bad programming courses, yes. From syntax errors, no. Students need some early signal as to what professional coding looks like, just not in the first semester. |
Is the second semester really better? | At that point, they have an opportunity to take what they learned about problem solving to other disciplines. Proceeding in a slow and steady way, systematically, works in many disciplines. Rushing almost always causes oodles of mistakes. |
Fair enough. | So what we take from Java are elements that support our the teaching of design principles. |
Please elaborate. | In Fundamentals 1, students learn that they must choose a data representation for the information that programs process. For example, how is mouse click represented? In Fundamentals 2, they learn to use classes as the most basic form of data representation and to combine it with functionality in the very same location. |
And? | An interface is the type of a data representation that requires more than one class. Consider currency as a simple idea. We definitely want an interface to have a uniform way of processing US dollars, Canadian dollars, Australian dollars, European dollars, and so on. |
They have euros over there. | Same thing. The key is that all variants of data should have a common interface, or what PL people call a type. (This is not what Java calls a type but they made a mistake.) |
Is there more? | If variants of data share functionality, create an abstract class and use inheritance to inject it into the concrete classes. It’s the one good use of inheritance. |
Really? | Even Josh Block says “favor composition over inheritance.” |
What does he mean with this? | A developer should not use inheritance for code reuse but for abstraction. For everything else, a developer should create a class with a field that points to the class that is to be re-used. |
And then? | The methods in the new class delegate work to the referenced class as needed, and they usually add a bit of computation. |
Does Fundamental 2 teach this? | It does. And creating composite classes and methods is the best way to keep every unit of code concise and comprehensible. |
Interesting. I thought object-oriented programming is the kind of programming I encountered in my CS1 with loops and assignment statements inside of methods and classes. | Our area has learned a lot about proper program design over the last few decades. |
But Fundamentals 2 does teach assignment statements? | Of course. Even “How to Design Programs” used to come with chapters about assignment statements. On occasion a software system needs to deal with changes to the state of an object. |
And loops? | If Java’s design had been based on the research of the design-patterns community, no. Java would have methods called while and for for any composite class just like it has methods called filter and map and so on for its Stream class. |
You say. | Guy Steele says. He wrote the first complete specification for Java and has argued for proper method calls for three decades. |
I think I have heard this name before. | Yeah, he’s kind of the superstar of language specification books. |
So we teach while and for loops? | Fundamentals 2 covers these old-fashioned concepts for several weeks. Students may encounter them in other languages, too. And again, the course explains carefully when these things are needed and when not. And how to use them. |
Thanks for all this information. | You’re welcome. |
5 Does it work?
One last question. Does our curriculum actually work? | There are interesting evaluation results for many aspects of our curriculum. |
Really? Is it possible to evaluate the effectiveness of a course on programming? | Decades ago, before any of us worked on this curriculum, someone came up with a class of programming problems that they thought a novice could solve after an introduction. |
Is this a well-known idea? | Time and again, people have published about the troubles with “rainfall problems.” |
And? Were students able to solve them? | Our students are far more likely to solve this kind of problem than students going through an ordinary curriculum. |
Why? What kind of difficulties do students encounter? | The original problem statement uses I/O. And beginning students have trouble with I/O, which is why Beginning Student Language avoids it and allows students to work with data directly. |
Ah, we are cheating. | No, we’re helping novice students. Besides when instructors avoid I/O in traditional settings, students still don’t do well. |
How much better are our students? A couple of percentages? | No, by factors. |
Ouch. | But there’s more. |
Like what? | Kathi, the researcher who ran the rainfall investigation, also studied error message comprehension. |
That’s an interesting technical language problem. | It is. Her PhD student Guillaume analyzed the reactions of hundreds of beginners to error messages. |
How did he do this? | Guillaume logged students behavior with modifications of the IDE. His findings are truly interesting. |
Did Beginning Student Language do well? | We hoped so, but not completely at the time. His findings uncovered a bunch of weaknesses. |
Finally. I was afraid everything is perfect around here. | He also worked out solutions. WeScheme is still better than Beginning Student Languages, but he fixed our problems as much as he could. |
Okay. Are we done? | There’s one more really neat result. |
Tell me. | We think that not all novice programmers will want to go on and become software developers. |
I agree. So? | Every student should get something out of a first course. |
Of course. They should know how to code a bit. Like the basics: variables; assignments; conditionals; loops. Everyone needs this. | This is not our thinking. We hope that students get a better understanding of basic algebraic concepts, especially functions and relations. |
Functions and relations? Why would anyone care in this day and age? | Longitudinal studies have shown that, everything else being equal, professional income by a person’s mid-30s is directly correlated to an understanding of these concepts. |
Huh? | It seems to be about systematic problem solving of word problems. |
And how did Beginning Student Language do? | It is not about the language per se. |
What is it about then? | Emmanuel Schanzer EdD dissertation at Harvard shows that teaching our curriculum in high school substantially increases student’s problem-solving skill in algebra. There’s real, validated transfer of skills. |
Northeastern is not a high school. | Sure, but our design-oriented curriculum helps freshman students in a similar ways. |
Can you explain? | The point of the first two courses is to go slow and steady when solving problems. Check each step. Reassure yourself that there’s progress. When stuck, work through examples. |
Okay. | You’re far more likely to succeed than with a rushed approach. |
I can see this. But do we explain this to students? | Instructors who know how to teach the courses ask students explicitly to write up how a journalist, a surgeon, an accountant or whatever may go about solving problems with the basic steps of the design approach. |
The word “design” doesn’t seem to match this. | Perhaps, but we are not the only ones who use it this way. |
Are there really others who teach our way? | Some. The real point is that people we don’t know and people we haven’t trained or even spoken to think that teaching systematic design is the way to go. |
Like who? | Shapiro, DesPortes, and DiSalvo wrote a nice column in Communications of the ACM. It’s worth reading. |
I’ll put it on my list. | Also check out what Mark Guzdial writes. |
Why? | He’s an recognized expert in programming education, and he really disliked our design-oriented approach in Beginning Student Language and Java. |
Are you finally providing evidence that it doesn’t work? | Nah. Once Guzdial actually studied it and understood it, he fully embraced it. |
I knew it. | He wrote a column for CACM for years. Time and again, he praised our curriculum design in his columns. You may want to read those. |
6 Python
It’s all fine. I now understand. But we really need to teach Python and loops and assignment statements as early as possible. | Why? |
Because everyone else does it, and it’s what our teaching faculty want to teach. | Okay. |