Teaching Clojure to beginning programmers: Functions before “variables”
tl;dr While creating a brief Clojure tutorial for people with zero programming experience — A Gentle Introduction to Clojure Through Turtles — we realize that we should be teaching functions all the way down.
As in probably all such courses in any language normally taught to beginners, the concept of a “variable” was introduced very early on in the curriculum:
var favoriteNumber = 5;
And look, we can change it (hence the term “variable” — watch it vary!):
console.log(favoriteNumber); // => 5 favoriteNumber = 6; console.log(favoriteNumber); // => 6
This was certainly the order in which I learned these language features X years ago when I first taught myself BASIC and Pascal, so I didn’t think to question it — even when most of the beginners displayed noticeable pain and confusion at having the equals sign they had learned in second grade repurposed as this strange new thing called the “assignment operator”.
It was one of many humbling eye-openers for me, as I watched people grappling with things I learned a long time ago in a galaxy far, far away.
As will probably be clear by now, I had never taught a class before.
Clojure: functions before vars
The weekend after the class was over, I volunteered with ClojureBridge — an organization working to increase diversity in the community around the Clojure programming language, by facilitating one-day beginner-friendly workshops in Clojure, for women.
(It’s based on its successful predecessor, RailsBridge, whose purpose is to… well, you get the idea.)
Our instance of the workshop — ClojureBridge NYC — was organized by Stuart Sierra of Cognitect, who did a great job putting it together and organizing the volunteers. I and Brian Gruber (an engineer at Meetup) were assigned to lead the beginner group — the people with no programming experience whatsoever.
I was very curious to see how this would go, as Clojure is a language dear to my heart but not one that’s normally taught to beginners. I think one of the primary reasons for that is that it’s not normally used by beginners, so the tooling and the ecosystem around it are mostly for experienced programmers. But we’d be introducing it with a recently-developed beginner-friendly IDE, Nightcode, so I had high hopes.
Brian and I decided that while the extensive slides provided by the ClojureBridge organization are really good for people who were at least a little bit familiar with another programming language and wanted an overview of Clojure — they go over the basics of the language, the syntax, and a few of the main data types, and culminate in some turtle graphics using a small app written for the occasion — we needed to come up with a supplemental lesson plan for total beginners. Ideally, this lesson plan would accomplish two goals in the few hours that we had with the workshop participants: 1) Show them how to do something cool, and 2) Give them a reason why they might want to continue studying Clojure (or programming of any kind) in the future.
To that end, we decided to skip the list of datatypes, and skip even talking about what a datatype is, and jump straight to the turtles, in the interest of providing immediate visual feedback.
Brian put together a basic outline, and my plan was to flesh it out into a README. Here was the outline:
- Have fun with turtles
- Learn about programming
- Learn about turtles
- Hello World — print something
- Turtles — forward, right, left, make some shapes
- Arithmetic — +, -, *, / — then use arithmetic in turtle commands (stealth intro to function composition!)
def— assign names to values
defn— assign names to values which also happen to be functions
- More fun with turtles — reuse code using
- Culminating exercise — make a function to draw a polygon of arbitrary size and arbitrary number of sides.
It looked great to me, and I fleshed out a basic README for the students, but when we looked at my end result, we realized something — it wasn’t doing a very good job of explaining why anyone would ever want to use
def, in these very simple examples. The best I could come up with was “in case you forget what angle 90 degrees is”:
;; make a square (def right-angle 90) (forward 50) (right right-angle) (forward 50) (right right-angle) (forward 50) (right right-angle) (forward 50) (right right-angle)
And indeed, when I later showed something like this code sample to beginners in the workshop, their reaction was usually along the lines of, but 90 is shorter to type. In other words, why would you want to give a second name to something (“right-angle”), when you already have its original name (“90”) that more clearly indicates the nature of the value in question? (Of course, it would be different if we were dealing with long strings instead of short numbers, but that wasn’t the case here.)
Functions, on the other hand — the thing that is taught much later in most programming classes — were quite easy to explain the purpose of. Even functions that are purely used for side effects and take no arguments are obviously useful to eliminate code repetition:
;; make a square (defn draw-square  (forward 50) (right 90) (forward 50) (right 90) (forward 50) (right 90) (forward 50) (right 90))
And then when you start parameterizing them, their power becomes obvious:
;; make a square of any size! (defn draw-square [size] (forward size) (right 90) (forward size) (right 90) (forward size) (right 90) (forward size) (right 90))
How did ClojureBridge go?
As it turned out, we had a particularly excellent volunteer turnout, so after I gave an hour-long lecture from the existing curriculum to everyone — beginners and experienced programmers alike — for the rest of the day every student pretty much had an individual tutor.
As someone who had just taught a ten-week course to people of wildly different experience levels, to all of whom I was supposed to have taught the same material to by the end, this was a dream. Everybody got to work on exactly what they wanted to, at their own pace, with as little or as much guidance as they wanted and with multiple mentors hanging around to answer questions at all times. A good time was had by all.
As for the beginner’s supplement that we wrote, I was actually scrambling to finish it during the workshop, so it never got used in its entirety, but we used enough of the concepts in practice with the workshop participants to confirm that we had been right in our intuition that
defn should come before
def. Here is the end result, slightly fixed up since the workshop:
Help out ClojureBridge
Want to increase diversity in the Clojure community by volunteering with ClojureBridge? You can go here to find out what’s already going on in your city, or to find out how to organize your own ClojureBridge event!