Audience: the list this was sent to was primarily BlueJ users, many of whom use BlueJ to introduce Java in a second term or late in the first term after spending time in Scheme.

Different Scheme approaches

Quoth Prabhakar Ragde:

I would be interested, Don, in your comparison of Brown's CS 017 to TeachScheme!, and in how your own CS1 takes ideas from each. Here are my problems with 017: no programming methodology; an SICP-influenced approach to Scheme (without the domain knowlege, but with a fairly steep introduction of features); and, most importantly, not a lot of connection from one language to the next, so it's more like "here's what Scheme is good for; here's what ML is good for, etc." rather than a smooth and planned transition.

Now I'm curious how you know so much about 17, but your analysis sounds pretty accurate. It was definitely SICP-inspired; we hadn't even heard of TeachScheme! when we started developing it in early 1998, although DrScheme was investigated as a possible IDE. (And rejected, for reasons I don't really remember.) More importantly, it was *really* a reaction to CS 15, and the professors developing it were an AI researcher who had really strong LISP programming skills and was moderately fluent in other languages, and a theoretician who didn't program much at all. A major design goal, which is to some extent shared with TS!, is to write programs from the bottom up, so that everything the student writes is *theirs*, and they understand the whole program. Another major goal, not at all shared with TS!, was to touch on basics of several different CS subfields, in the same way that an Intro to Biology class might give students a taste of macrobiology, cytobiology, botany, and zoology. Our first-term final project involved writing a minimax AI for a basic zero-sum game like Checkers or Othello. We introduced analysis and big-O notation early in the first term. Software engineering principles were discussed throughout.

Probably the biggest single thing I liked about TeachScheme! was the introduction of the design recipe. I find that it's a really useful way to methodicalise the process of thinking about programming, at least for the beginning programmer, although I find myself going back and revising my own habits to include things like writing examples of data before writing code. It helps! There was no question that however else I taught an intro CS class, a design recipe would be involved somehow.

Another biggie was the idea of deferring lambda until later. In 17, we rejected SICP's use of the

  (define (average x y) ...)
syntax, teaching functions right off the start as
  (define average
    (lambda (x y) ...))
Why hide the fact that this was no different than (define n 5)?* The idea of functions as first-class values was one we introduced implicitly from the start, and explicitly not much later than that; we kept hammering it for the rest of the term. I know we moved to ML right after midterms, and the students had already written map, filter, and fold by that point. The project culminating the Scheme unit was "Schemeleh" ("little Scheme"), wherein students wrote an interpreter for a fairly substantial subset of Scheme.

At the time, I (and the undergrad TAs) found this really exciting; to be honest, I hadn't done much with functional languages before, and so for all of us TAs this was our revelatory "functional programming is SO COOL" phase. I'm not sure what the professors were thinking. And to be fair, the class kept up pretty well, so I don't think it was necessarily a bad choice. However, I also like how TS! motivates why we might possibly *want* higher-order functions before actually introducing them.

The transitions between the languages weren't quite so abrupt as you say, though. From Scheme to ML, we introduced the notion of strong typing, then pointed out that Scheme doesn't do that, but here's a language that has *really* strong typing, let's learn that now. At the start of 18, we went back to Scheme for about a week, introduced mutation and reference semantics (hello, box-and-pointer diagrams!), and then pointed out that Scheme wasn't designed for that and is a little clunky, but here's a language that mutation is more paradigmatic for, let's learn that now. (In retrospect, it should have been a week of mutation and reference semantics, *then* a bit of OO, and "but Scheme doesn't do that, so...." And maybe that's how they do it now. I haven't followed 17/18 very closely for a few years.)

*The problem with this reasoning, namely that there's a bit of magic either way, as in

  (define fact
    (lambda (n)
      (if (zero? n) 
          1 
          (* n (fact (- n 1))))))
---inside the lambda, where is fact defined?---was not made clear to me until quite a bit later.

Betwen 015 and 017, the choice is clear to me, but one thing I took from Brown's setup is that there should be a choice. Our Scheme-Java stream is a voluntary alternative to the mainstream Java sequence. I can't imagine it working for a student who feels they are forced to take "useless" Scheme as opposed to "useful" Java. --PR

It would be nice if we could do two separate intro tracks, but I'm currently teaching at a small college with just 3 CS faculty---no chance. Ironically, just two years before I arrived the intro sequence was switched from Scheme to Java, purportedly on the basis of "practicality". I rejected the basis wholeheartedly, and I say on day one that my course is not there to provide them with job skills. However, there was a lot of irrational hatred of Scheme when I got here, and from some discussions with older students I suspect it was very poorly taught; probably a "lots of big smart schools start in Scheme, so we should too", without a lot of consideration for *why* one might choose Scheme.

Anyway, so I was pretty locked in to Java here. In the first year I taught, I tried to use a more-or-less TS!-like strategy (design recipes, etc) to teach a class that was kind of like 17/18 except all in Java, while making some concession to the order the textbook presented things in. It was far from a total failure, but a lot of things could have gone better.

First of all, the book was a big problem. I eventually abandoned it entirely; it's just too hard to (say) teach recursion instead of iteration when recursion is relegated to an appendix or omitted entirely. You simply can't put off mutation for any significant length of time. Basically, the book dictates the conceptual progression, and there's no good textbook (yet) that is in Java but follows a TS!-ish line. The TS! folks are writing a book for graduates of TS!, but even that's not going to work for me, so I've written a course pack that's kind of like a textbook except without as many exercises. It's certainly an interesting experience.

The clash between the 17 style and the TS! style was harder to tease out, and I still haven't fully resolved how to deal with it. Basically, I sometimes feel like TS! takes its own advice too seriously: "deal with the easy stuff now, put the rest off until later". Access control? Later. Mutation? Later. Static methods? Later. Overloading? Later. Thing is, I completely agree. I think that's exactly right. In my second year of teaching, after attending the "How to Design Class Hierarachies" workshop, i.e. "How to teach a second-term Java course after a first term in TeachScheme!", I clarified a lot of ideas on how to present the TS! pedagogy in Java, and went whole-hog in that direction. Less students dropped my class, and of those that remained, more were really on board through the end of the class. It *is* a better way to teach. At the same time, I sometimes feel like I'm back to teaching programming---in a much better way, mind you!---and away from the "Intro to Computer Science, not Intro to Programming" motto that I so loved about CS 17/18. On the other hand, although my students may have less exposure to e.g. analysis or AI now, I suspect they're much better in the areas of abstraction and problem solving. We'll see how they do in the later courses.

Don Blaheta / blahetadp@blahedo.org