Earlier this week I joined several other department heads to eat lunch with a bunch of high school teachers who were on campus for the Physics Olympics. The teachers were talking shop about the physics courses at their schools, and eventually the conversation turned to AP Physics. One of the teachers said, "It's a good course, but..."
A lot of these teachers would rather not offer AP Physics at all. One teacher described how in earlier days they were able to teach an advanced physics course of their own design. They had freedom to adapt to the interest of their students and to try out new ideas they encountered at conferences. Even though the advanced physics course had first-year physics as a prerequisite, they had plenty of students interested and able to take the second course.
The introduction of AP Physics created some problems. It's a good course, they all agreed, but it is yet another AP course for their students to take, and yet another AP exam for the students to prepare for. Most students can't or don't want to take all the AP courses, due to the heavier workload and often grueling pace. So in the end, they lose potential students who choose not to take the physics class.
Several of these teachers tried to make this case to heads of their divisions or to their principals, but to no avail.
This makes me sad. I'd like to see as many students taking science and math courses in high school as possible, and creating unnecessary bottlenecks hurts that effort.
There is a lot of cultural pressure these days to accelerate the work that HS students do. K-12 school districts and their administrators see the PR boon of offering more, and more advanced courses. State legislators are creating incentives for students to earn college credit while in high school, and funding for schools can reflect that. Parents love the idea of their children getting a head start on college, both because it might save money down the line and because they earn some vicarious pleasure in the achievement of their children.
On top of all this, the students themselves often face a lot of peer pressure from their friends and other fellow students to be doing and achieving more. I've seen that dynamic at work as my daughters have gone through high school.
Universities don't seem as keen about AP as they used to, but they send a mixed message to parents and students. On the one hand, many schools give weight in their admission decisions to the number of AP courses completed. This is especially true with more elite schools, which use this measure as a way to demonstrate their selectivity. Yet many of those same schools are reluctant to give full credit to students who pass the AP exam, at least as major credit, and require students to take their intro course anyway.
This reluctance is well-founded. We don't see any students who have taken AP Computer Science, so I can't commit on that exam but I've talked with several Math faculty here about their experiences with calculus. They say that, while AP Calculus teaches a lot of good material, but the rush to cover required calculus content often leaves students with weak algebra skills. They manage to succeed in the course despite these weaknesses, but when they reach more advanced university courses -- even Calc II -- these weaknesses come back to haunt them.
As a parent of current and recent high school students, I have observed the student experience. AP courses try to prepare students for the "college experience" and as a result cover a lot of material. The students see them as grueling experiences, even when they enjoy the course content.
That concerns me a bit. For students who know they want to be math or science majors, these courses are welcome challenges. For the rest of the students, who take the courses primarily to earn college credit or to explore the topic, these courses are so grueling that this dampen the fun of learning.
Call me old-fashioned, but I think of high school as a time to learn about a lot of different things, to sample broadly from all areas of study. Sure, students should build up the skills necessary to function in the workplace and go to college, but the emphasis should be on creating a broadly educated citizen, not training a miniature college student. I'd rather students get excited about learning physics, or math, or computer science, so that they will want to dive deeper when they get to college.
A more relaxed, more flexible calculus class or physics course might attract more students than a grueling AP course. This is particularly important at a time when everyone is trying to increase interest in STEM majors.
My daughters have had a lot of great teachers, both in and out of their AP courses. I wish some of those teachers had had more freedom to spark student interest in the topic, rather than student and teacher alike facing the added pressure of taking the AP exam, earning college credits, and affecting college admission decisions
It's a good course, but feel the thrill first.
We are deep in the semester now, using Racket in our programming languages course. I was thinking recently about how little of Racket's goodness we use in this course. We use it primarily as a souped-up R5RS Scheme and handy IDE. Tomorrow we'll see some of Racket's tools for creating new syntax, which will explore one of the rich niches of the system my students haven't seen yet.
I'm thinking about ways to introduce a deeper understanding of The Racket Way, in which domain concepts are programming language constructs and programming languages are extensible and composable. But it goes deeper. Racket isn't just a language, or a set of languages. It is an integrated family of tools to support language creation and use. To provide all these services, Racket acts like an operating system -- and gives you full programmatic access to the system.
(You can watch the video of Flatt's StrangeLoop talk "The Racket Way" at InfoQ -- and you should.)
The idea is bigger than Racket, of course. Dan Ingalls expressed this idea in his 1981 Byte article, Design Principles Behind Smalltalk:
Operating System: An operating system is a collection of things that don't fit into a language. There shouldn't be one.
Alan Kay talks often about this philosophy. The divide between programming language and operating system makes some things more difficult for programmers, and complicates the languages and tools we use. It also creates a divide in the minds of programmers and imposes unnecessary limitations on what programmers think is possible. One of things that appealed to me in Flatt's StrangeLoop talk is that presented a vision of programming without those limits.
There are implications of this philosophy, and costs. Smalltalk isn't just a language, with compilers and tools that you use at your Unix prompt. It's an image, and a virtual machine, and an environment. You don't use Smalltalk; you live inside it.
After you live in Smalltalk for a while, it feels strange to step outside and use other languages. More important, when you live outside Smalltalk and use traditional languages and tools, Smalltalk feels uncomfortable at best and foreboding at worst. You don't learn Smalltalk; you assimilate. -- At least that's what it feels like to many programmers.
But the upside of the "programming language as operating system" mindset you find in Smalltalk and Racket can be huge.
This philosophy generalizes beyond programming languages. emacs is a text editor that subsumes most everything else you do, if you let it. (Before I discovered Smalltalk in grad school, I lived inside emacs for a couple of years.)
You can even take this down to the level of the programs we write. In a blog entry on delimited continuations, Andy Wingo talks about the control this construct gives the programmer over how their programs work, saying:
It's as if you were implementing a shell in your program, as if your program were an operating system for other programs.
When I keep seeing the same idea pop up in different places, with a form that fits the niche, I'm inclined to think I am seeing one of the Big Ideas of computer science.
After eighteen printed pages showing the wonders of APL in A Glimpse of Heaven, Bernard Legrand encourages programmers to give the language a serious look. But he cautions APL enthusiasts not to oversell the ease of learning the language:
Beyond knowledge of the basic elements, correct APL usage assumes knowledge of methods for organising data, and ways specific to APL, of solving problems. That cannot be learnt in a hurry, in APL or any other language.
Legrand is generous in saying that learning APL takes the same amount of time as learning any other language. In my experience, both as a learning of language and as a teacher of programmers, languages and programming styles that are quite different from one's experience take longer than more familiar topics. APL is one of those languages that requires us to develop entirely new ways of thinking about data and process, so it will take most people longer to learn than yet another C-style imperative language or OO knock-off.
But don't be impatient. Wanting to move too quickly is a barrier to learning and performing at all scales, and too often leads us to give up too soon. If you give up on APL too soon, or on functional programming, or OOP, you will never get to glimpse the heaven that experienced programmers see.
Alan Kay recently wrote this on the Fundamentals of New Computing mailing list:
My own personal thoughts about what was accomplished [with Smalltalk] are completely intertwined with what our entire group was able to do in a few years at PARC. I would give us credit for a very high level combination of "computer science" and "software engineering" and "human centered design" and "commingled software and hardware", etc. The accomplishment was the group's accomplishment. And this whole (to me at least) was a lot more interesting than just a language idea.
I hasten to redirect personal praise to the group accomplishment whenever it happens.
I think this is also true for the larger ARPA-PARC community, and why it was able to accomplish so much at so many levels.
The "awards to individuals" structure beloved of other fields and of journalists completely misses the nature of this process. Any recognition should be like "World Series" rings -- everybody gets one, and that's it.
When Kay spoke at the 2004 OOPSLA Educators' Symposium as part of his Turing Award festivities, he frequently acknowledged the contributions of his team, in particular Dan Ingalls, and the influence that so many other people had on his team's work. Kay must have particularly appreciated receiving the Charles Stark Draper Prize together with Butler Lampson, Robert Taylor, and Charles Thacker, who helped create the conditions in which his team thrived.
In academia, we talk a lot about teamwork, but we tend to isolate individual performance for recognition. I like Kay's analogy to the rings received by teams that win sports championships. In those venues, the winners are unmistakably teams, even when a Michael Jordan or a Tom Brady stands out. That's how academic research tends to work, too. Perhaps we should make that clear more often in the awards we give.
In year or so, I have seen a few people write to debunk the idea that Lisp is special because its code is written in the primary data structure of the language, list. The one I remember best is Dave Herman's Homoiconicity isn't the point, which points out that the critical technical feature that makes Lisp syntax powerful is that it can be read without being parsed.
This morning I read an old Slashdot post in which Lisp guru Kent Pitman gives a more philosophical answer to the question about what makes Lisp's syntax so special:
I like Lisp's willingness to represent itself. People often explain this as its ability to represent itself, but I think that's wrong. Most languages are capable of representing themselves, but they simply don't have the will to.
That's a nice turn of phrase:  : Lisp is willing to represent itself in data, whereas most languages don't have "the will" to do so. It's not about possibility, but facility.
It's easier to manipulate and generate programs from inside a Lisp or Scheme program than any other language that most of us might see on a daily basis. Rubyists manipulate nested arrays of symbols that encode abstract syntax trees, but this style feels somewhat artificial, and besides Ruby's syntax is so large that it's hard for a Ruby program to process other Ruby programs in this way.
As Pitman says, the fact that Lisp programs are represented by lists is almost besides the point. It might well have been arrays of some other data structure. The key is that it is the program's structure being represented, and not the character-level syntax of the programs. This is the same reason that code can be read without being parsed, and that the macro system can be so powerful.
It's also what makes it so easy to provide powerful support for programmers in their text editors and other tools. These tools don't require a lot of machinery or runtime to navigate and manipulate program code. The structure of the code lies close to its surface.
In the end, I like have two ways to think about Lisp's and Scheme's syntactic advantages: the technical reasons that live in the read procedure and the visceral reasons that embody how programmers feel will they work with a syntax that is willing to help the programmer.
In Good for Whom?, Daniel Lyons writes about the readability of code. He starts with Dan Ingall's classic Design Principles Behind Smalltalk, which places a high value on a system being comprehensible by a single person, and then riffs on readability in J and Smalltalk.
Early on, Lyons made me smile when he noted that, while J is object-oriented, it's not likely to be used that way by many people:
... [because] to use advanced features of J one must first use J, and there isn't a lot of that going on either.
As a former Smalltalker, I know how he feels.
Ultimately, Lyons is skeptical about claims that readability increases the chances that a language will attract a large audience. For one thing, there are too many counterexamples in both directions. Languages like C, which "combines the power of assembly language with the readability of assembly language" [ link ], are often widely used. Languages such as Smalltalk, Self, and Lisp, which put a premium on features such as purity and factorability, which in turn enhance readability, never seem to grow beyond a niche audience.
Lyons's insight is that readability can mislead. He uses as an example the source code of the J compiler, which is written in C but in a style mimicking J itself:
So looking at the J source code, it's easy for me to hold my nose and say, that's totally unreadable garbage; how can that be maintained? But at the same time, it's not my place to maintain it. Imagine if it were written in the most clean, beautiful C code possible. I might be able to dupe myself into thinking I could maintain it, but it would be a lie! Is it so bad that complex projects like J have complex code? If it were a complex Java program instead, I'd still need substantial time to learn it before I would stand a chance at modifying it. Making it J-like means I am required to understand J to change the source code. Wouldn't I have to understand J to change it anyway?
There is no point in misleading readers who have trouble understanding J-like code into thinking they understand the compiler, because they don't. A veneer of readability cannot change that.
I know how Lyons feels. I sometimes felt the same way as I learned Smalltalk by studying the Smalltalk system itself. I understood how things worked locally, within a method and then within a class, but I didn't the full network of classes that made up the system. And I had the scars -- and trashed images -- to prove it. Fortunately, Smalltalk was able to teach me many things, including object-oriented programming, along the way. Eventually I came to understand better, if not perfectly, how Smalltalk worked down its guts, but that took a lot of time and work. Smalltalk's readability made the code accessible to me early, but understanding still took time.
Lyons's article brought to mind another insight about code's understandability that I blogged about many years ago in an entry on comments in code. This insight came from Brian Marick, himself no stranger to Lisp or Smalltalk:
[C]ode can only ever be self-explanatory with respect to an expected reader.
Sometimes, perhaps it's just as well that a language or a program not pretend to be more understandable than it really is. Maybe a barrier to entry is good, by keeping readers out until they are ready to wield the power it affords.
If nothing else, Lyons's stance can be useful as a counterweight to an almost unthinking admiration of readable syntax and programming style.
We have all been there:
Somehow, at some point in every serious programming project, it always comes down to the last option: stare at the code until you figure it out. I wish I had a better answer, but I don't. Anyway, it builds character.
This is, of course, the last resort. We need to teach students better ways to debug before they have to fall back on what looks a lot like wishful thinking. Fortunately, John Regehr lists this approach as the last resort in his lecture on How to Debug. Before he tells students to fall back to the place we all have to fall back to occasionally, he outlines an explicit, evidence-driven process for finding errors in a program.
I like that Regehr includes this advice for what to do after you find a bug: step back and figure out what error in thinking led to the bug.
An important part of learning from a mistake is diagnosing why you made it, and then taking steps wherever possible to make it difficult or impossible to make the same mistake again. This may involve changing your development process, creating a new tool, modifying an existing tool, learning a new technique, or some other act. But it requires an act. Learning rarely just happens.
Student: "I didn't have time to write 150 lines of code for the homework."
Master: "That's fine. It requires only 50."
Student: "Which 50?"
I have lived this story several times recently, as the homework in my Programming Languages has become more challenging. A few students do not complete the assignment because they do not spend enough time on the course, either in practice or performance. But most students do spend enough time, both in practice and on the assignment. Indeed, they spend much more time on the assignment than I intend.
When I see their code, I know why. They have written long solutions: code with unnecessary cases, unnecessary special cases, and unnecessary helper functions. And duplication -- lots and lots of duplication. They run out of time to write the ten lines they need to solve the last problem on the set because they spent all their time writing thirty lines on each of the preceding problems, where ten would have done quite nicely.
Don't let anyone fool you. Students are creative. The trick is o help them harness their creativity for good. The opposite of good here is not evil, but bad code -- and too much code.