Skip to content

Teaching Clojure to beginning programmers: Functions before “variables”

2016 August 5
by Richard Harrington

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.

JavaScript: Variables before functions

A couple of weeks ago, I finished teaching a ten-week, part-time JavaScript course at General Assembly in New York. There was a range of experience levels in the class, and while most of the students knew some HTML and CSS, the majority were completely new to the concept of programming — of bending a computer to their will.

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

We didn’t get to the topic of functions — and creating our own functions — until several more lessons had passed, and we’d already gone over every single data type and control flow structure in the JavaScript language (or ES5, anyway).

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.

In the end everybody lived happily ever after, everybody learned to love variables and functions in JavaScript, and I like to think we all (including me!) learned a little bit more than we did before about how to solve problems with code. And we may also have learned a tiny bit about the evils of mutating data willy-nilly, although that’s a more elusive concept to get across.

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:

Objectives:

  1. Have fun with turtles
  2. Learn about programming
  3. Learn about turtles

Steps:

  1. Hello World — print something
  2. Turtles — forward, right, left, make some shapes
  3. Arithmetic — +, -, *, / — then use arithmetic in turtle commands (stealth intro to function composition!)
  4. def — assign names to values
  5. defn — assign names to values which also happen to be functions
  6. More fun with turtles — reuse code using dotimes
  7. 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))

And I think this is the best way to start introducing the concept of binding names to values. Function arguments seem much more obviously useful to a person on their first day of programming than the top-level vars that most closely resemble global variables in JavaScript.

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:

A Gentle Introduction to Clojure Through Turtles

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!

Leave a Reply

Note: You may use basic HTML in your comments. Your email address will not be published.

Subscribe to this comment feed via RSS