Here are the courses I am currently teaching:

CS 1x (Intermediate Computer Programming)

This course is an alternative to CS 1 for students with significant prior programming experience. It uses Java, emphasizes the program design process, and prepares students to take CS 2.

CS 4 (Fundamentals of Computer Programming)

This course is an introduction to functional programming using the OCaml language. Functional programming is fascinating in its own right, and a knowledge of OCaml is also a prerequisite for the CS 131 and CS 164 courses described below.

CS 11 (Computer Language Shop)

CS 11 is a grab-bag of mini-courses. I teach two of these:

  • C track

    This course covers the basics of the C language. It’s good preparation for the CS 24 course and/or for CS 3, both of which use C. Knowledge of C is a critical survival skill for programmers, even if you don’t end up doing a lot of C programming.

  • Rust track

    This course covers the Rust programming language, which is a systems-level programming language with an unusually high abstraction level and an even more unusual emphasis on safety. Rust is one of the most interesting languages to emerge in recent years, and is becoming a serious challenger to C and C++ for computation-intensive tasks.

CS 115 (Functional Programming)

This course is a second functional programming course (after CS 4), this time using the Haskell programming language. Haskell is an incredibly rich language, but it has a reputation of being very hard to learn because the abstraction level is so high and the concepts are so foreign. This course de-mystifies the language, explaining the hard parts carefully so that you can enjoy the powerful abstractions without getting hopelessly confused.

CS 128 (Interactive Theorem Proving)

This course is an introduction to the field of interactive theorem proving using the Coq proof assistant. Proof assistants are a fascinating way of doing proof-based mathematics; this basically involves writing programs in an unusual programming language in order to prove theorems rigorously (and have the computer check that the proof is correct and complete). This is a great course for math students and for more mathematically-inclined CS students. It will open your mind to a whole new way of thinking about proofs!

CS 131 (Interpreters)

The easiest way to learn about implementing programming languages is to write an interpreter for a programming language. In this course, we write several interpreters for both imperative and functional languages. Some of the languages are untyped, some dynamically typed, and some statically typed. We also cover the theoretical basis of programming language implementation (operational semantics) and show how you can go from an abstract mathematical description of an evaluator or a type checker to working code.

CS 164 (Compilers)

Compilers are the next logical step after interpreters. A compiler is like an interpreter in that it transforms code into a different representation, but unlike interpreters, the last stage isn’t an evaluator but actual assembly language code which can (after assembly) be run directly on the computer. Because the gap between the source language and the target assembly language is so large, multiple transformation passes have to occur in sequence to compile source code to assembly language. In addition, optimizations can occur at any level. Compilers are fascinating, and building a compiler helps to tie together many disparate aspects of a computer science education in a project which illustrates the relevance of much of the material you’ve already learned. In addition, a compiler is a large scale programming project which is challenging from a software engineering standpoint as well.