Programming Languages, Part A
This is the first blog post I've written about OSSU where I don't have to explain why I failed so miserably to meet my goals, and that feels really good. I finished the course about a week earlier than planned:
This is another course that I thoroughly enjoyed. It hit that sweet spot where the content was difficult enough to be challenging, but not so difficult that it was discouraging.
I completed this course using both a MacBook and a Windows 10 laptop. Setup was not nearly as hard as the course made it sound, though that might be in part because I used Visual Studio Code instead of Emacs. I already use VSCode on a daily basis and didn't see a good reason to learn Emacs.
Setup on Windows was really easy. I just installed SML and this extension (for VSCode): SML Environment. I used the SML REPL from the terminal in VSCode.
Setup on MacOS was a little more complicated, but not terribly so:
- SML installed fine, though it uses Rosetta since (as of now) there is no native SML compiler for Apple Silicon. I did not experience any performance issues or bugs but the stuff you program in this course is not terribly large or complicated, so I can't say whether or not the Rosetta layer would be an issue if you were doing something more complex.
- The default shell in MacOS is zsh now, not bash. All I had to do was add a PATH export in my ~/.zshrc file:
- There was an issue using command history (actually anything involving the arrow keys) in the SML REPL. For example, if I pressed the up arrow key to get my previous command, a bunch of random characters would appear instead. Evidently this has been an issue for a long time. My solution was to install rlwrap and then run the SML REPL like this: rlwrap sml
I created a new repo in Github and used git to keep my notes and homework in sync between my Windows and Mac laptops.
I settled into a routine pretty quickly, and I think it worked pretty well:
- Watch all videos at 1.5x speed, taking notes and programming along. Rewatch any videos where the material was harder to grasp.
- Skim through the section summary, paying particular attention to topics that were difficult to understand in the videos.
- Do the homework, referencing the section summary and SML language documentation when I get stuck.
The homework assignments in this course were incredibly important. I started each one with a 70-80% grasp of the week's material and finished feeling very confident in the material. Everything sort of clicked into place as I worked through the problems. This was particularly true of concepts like lexical scope and closures.
In my opinion the peer reviews were almost equally important. I didn't get a lot of good peer review feedback - sometimes it was even frustrating - but the process of reading other students' code and critiqueing it was really helpful. I saw code that was both worse and better than my own, and then had to articulate what specifically was good or bad about that code. This granted me additional clarity that I didn't have even after completing the homework myself.
Tests are still really important
The test file you get for each homework is nowhere near exhaustive. You are expected to write more tests for each of your functions. I passed each homework the first time I turned it in, and this would not have happened if I didn't first write a bunch of good tests for each of my functions. These tests also helped me identify issues with other students' code during peer reviews.
I got slightly lazy about this in homework 3, and it cost me some time and effort. You have to write a helper function called longest_string_helper and the basic test file had no test for this function. I decided to skip writing tests for this function as well. When I turned in my work to the autograder, I passed (i.e. scored more than 80%) but was surprised to see that I was docked points even though all my tests passed.
After carefully re-reading the relevant homework problem, looking at the sample solution, and looking at the type that SML inferred for my function, I realized that I had slightly misunderstood what the longest_string_helper function was supposed to do. In short, I needed to compare the size of two strings in my helper function, not in the functions that called my helper function. If I had written even a single good test for longest_string_helper it's likely I would have realized this immediately, because it probably would not have even type-checked. I wish I could show you the specifics here, but sharing this code is against the TOS for the course.
I jumped right into the next course, Programming Languages Part B, which should take about 3 weeks to complete. I am really enjoying the momentum I have right now, and while I don't expect to complete every OSSU course ahead of schedule, I am hoping to complete them at least within a week of my estimated finish date. Here's to hoping the 4-months-overdue phase of my OSSU studies was indeed just a phase.