So the Programming Languages course is just about over. There’s actually one peer assessment yet to go and it will probably be a few weeks until the course staff tabulates and releases the results, but all of the serious work is over. I wanted to get this post written before I start on two new courses next week. It’s run by Dan Grossman of the University of Washington and ran for 10 weeks. This course used a slightly different schedule than other Coursera courses which usually had weekly sections. For this course, the eight course sections were spread out over the ten weeks so we didn’t have a predictable schedule of when each section would be released.
The course used three different languages, starting with SML for the first four sections, Racket for the next two sections and ending with Ruby for the final two sections. There was a programming assignment for each section, with exception of section 4 when we had a mid-term exam. At the end of it all, we have the final exam which is still ongoing as of the time of writing. There were no other quizzes though each section’s programming assignment had to be submitted twice. Once to the autograding system to test for correctness and once again to the peer assessment system to check for style issues and correctness isssues for which it was difficult to get the autograder to test for. One cool thing is that most of the programming assignments have optional challenge questions which award a small number of bonus points for a comparatively huge amount of extra work, just for those who want to run the extra mile.
This had the effect than although I had no prior exposure to all three languages before the course, I eventually achieved reasonable proficiency in SML, some familiarity with Racket and almost no knowledge of Ruby. This is especially since the Ruby assignments either involved writing very little code or consisted of mostly porting provided SML code to Ruby. But it’s also because Ruby is such a big language with such an extensive library and so many ways to do things. Racket on the other hand was my first exposure to a Lisp-like language and involved learning very little syntax.
Of course this course isn’t about learning these three languages. It’s about using these languages to cover different concepts in the design of programming languages. So SML was used as an example of a statically typed language in the functional style and yet does not require explicit type declarations due to its type inferencing system. Racket is used as an example of a functional style dynamically typed language. Ruby is used an an example of a dynamically typed language with a full commitment to object-oriented programming.
Along the way we covered a ton of ground, including more recursion than I’ve ever done anywhere else plus how to do tail recursion correctly, higher-order functions, lexical scope, currying (which was a pretty mindbending concept to me), lazy programming and streams. I learned fewer new concepts in the last two sections since I was already reasonably familiar with OOP, but the course managed to convey why dynamic dispatch is actually kind of weird and why a full commitment to OOP requires double dispatch.
One thing worth noting is that judging from the forums, many people found this course to be very difficult, even people who have degrees in computer science and have worked for many years as a programmer. I didn’t see this type of response in Princeton’s Algorithms class for example which I still consider to be somewhat harder. The difference is probably that algorithms and data structures is a knowledge area that every programmer is expected to know while the concepts taught in this class probably won’t be relevant to most programmers unless they need to design a programming language or implement one.
The hardest assignments in the class demonstrate this. The challenge question in section three for example involved writing a type checking program. I found it very hard to even understand what the question was asking for though once I did understand it, implementing it wasn’t all that hard. Similarly in section 6, we had to use Racket to write an interpreter for a simple language designed by the professor, his so-called Made-Up-Programming Language (MUPL) and then write programs in MUPL and extensions to MUPL written as Racket macros. Pretty awesome stuff.
One minor complaint is that the autograder isn’t all that robust. Students have designed unit tests and made them available on the forums that catch errors in programs for which the autograder is content to assign full marks. Similarly in some cases the autograder tests for implementation details not covered in the specifications instead of just specified behavior which annoyed some students.
The grading system used here was also somewhat stricter than that I’ve seen elsewhere though of course this a conscious choice by the professor. The autograder is supposed to take the average of the first two non-zero scores as the effective score for each assignment. For each of the two exams, we had a mock practice exam that doesn’t figure into the final grade but we had only one attempt at the real exam. Contrast this with say Princeton’s Algorithms class which allowed three attempts at the final exam and basically as many submissions as you wanted for the programming assignments.
Finally, one of the greatest things about this course is that the professor wrote extensive notes for all of the lectures. They’re so detailed and exhaustive that some students chose to just read the PDF files instead of watching the video lectures. They basically amount to a free mini-textbook and constitute a very useful reference document on their own. Overall I’m very happy with the course. It really opened my eyes to the breadth of programming idioms out there and highlighted just how much more there is to learn. At the same time, it also demystified programming language implementation to me. I still can’t write an interpreter or a compiler for a real language of course but at least now I have some idea about how one would go about writing one.
My next two courses on Coursera are the long-awaited Algorithms II from Princeton, which I expect to be challenging, and Learn to Program: Crafting Quality Code from the University of Toronto. I expect the latter course to be less challenging which is why I’m trying to take two courses at the same time, but I might have to drop it if Algorithms II proves too time consuming. I really need to formally learn testing and debugging though because so far my only debugging tool is using print statements and I know nothing about using modern IDEs and their associated tools.
One thought on “End of Programming Languages class”