Alice: The hardest word you'll ever be asked to spell is "ichdericious".
Bob: Yikes. Which word?
A few of us have had fun with the quotations in English and Scheme over the last few days, but this idea is bigger than symbols as data values in programs or even words and strings in natural language. They are examples of a key element of computational thinking, indirection, which occurs in real life all the time.
A few years ago, my city built a new water park. To account for the influx of young children in the area, the city dropped the speed limit in the vicinity of the pool from 35 MPH to 25 MPH. The speed limit in that area has been 35 MPH for a long time, and many drivers had a hard time adjusting to the change. So the city put up a new traffic sign a hundred yards up the road, to warn drivers of the coming change. It looks like this one:
The white image in the middle of this sign is a quoted version of what drivers see down the road, the usual:
Now, many people slow down to the new speed limit well in advance, often before reaching even the warning sign. Maybe they are being safe. Then again, maybe they are confusing a sign about a speed limit sign with the speed limit sign itself.
If so, they have missed a level of indirection.
I won't claim that computer scientists are great drivers, but I will say that we get used to dealing with indirection as a matter of course. A variable holds a value. A pointer holds the address of a location, which holds a value. A URL refers to a web page. The list goes on.
Indirection is a fundamental element in the fabric of computation. As computation becomes an integral part of nearly everyone's daily life, there is a lot to be gained by more people understanding the idea of indirection and recognizing opportunities to put it to work to mutual benefit.
Over the last few years, Jon Udell has been making a valiant attempt to bring this issue to the attention of computer scientists and non-computer scientists alike. He often starts with the idea of a hyperlink in a web page, or the URL to which it is tied, as a form of computing indirection that everyone already groks. But his goal is to capitalize on this understanding to sneak the communication strategy of pass by reference into people's mental models.
As Udell says, most people use hyperlinks every day but don't use them as well as they might, because the distinction between "pass by value" and "pass by reference" is not a part of their usual mental machinery:
The real problem, I think, is that if you're a newspaper editor, or a city official, or a citizen, pass-by-reference just isn't part of your mental toolkit. We teach the principle of indirection to programmers. But until recently there was no obvious need to teach it to everybody else, so we don't.
He has made the community calendar his working example of pass by reference, and his crusade:
In the case of calendar events, you're passing by value when you send copies of your data to event sites in email, or when you log into an events site and recopy data that you've already written down for yourself and published on your own site.
You're passing by reference when you publish the URL of your calendar feed and invite people and services to subscribe to your feed at that URL.
"Pass by reference rather than by value" is one of Udell's seven ways to think like the web, his take on how to describe computational thinking in a world of distributed, network media. That essay is a good start on an essential module in any course that wants to prepare people to live in a digital world. Without these skills, how can we hope to make the best use of technology when it involves two levels of indirection, as shared citations and marginalia do?
Quotation in Scheme and pass-by-reference are different issue, but they are related in a fundamental way to the concept of indirection. We need to arm more people with this concept than just CS students learning how programming languages work.
My rumination on real-world examples of quotation to use with my students learning Scheme sparked the imaginations of several readers. Not too surprisingly, they came up with better examples than my own... For example, musician and software developer Chuck Hoffman suggested:
A song, he sang.
"A song", he sang.
The meaning of these is clearly different depending on whether we treat a song as a variable or as a literal.
My favorite example came from long-time friend Joe Bergin:
"Lincoln" has seven letters.
Lincoln has seven letters.
Very nice. Joe beat me with my own example!
As Chuck wrote, song titles create an interesting challenge, whether someone is singing a certain song or singing in a way defined by the words that happen to also be the song's title. I have certainly found it hard to find words both that are part of a title or a reference and that flow seamlessly in a sentence.
This turns out to be a fun form of word play, independent of its use as a teaching example. Feel free to send me your favorites.
The new semester is fully underway, and I'm already enjoying Programming Languages. My Tuesday session this week felt like a hodgepodge of topics, including Scheme definitions and conditionals, and didn't inspire my students much. Today's session on pairs and lists seemed to go much more smoothly, at least from my side of the classroom.
One thing that has been different the first two weeks this time around has been several questions about the quote character in Scheme, which is shorthand for the special form quote.
The purpose of the quote is to tell the interpreter to take its argument literally. When the argument is a list, say, '(* 2 3), quotation prevents the interpreter from evaluating the list as a Scheme procedure call. When the argument is a symbol, say, 'a, the quote lets the interpreter know not to treat the a as an identifier, looking up the value bound to that name in the current environment. Instead, it is treated as the literal symbol a. Most of our students have not yet worked in languages where symbols are first-class data values, so this idea takes some getting used to.
In the course of talking about quotation with them, I decided to relate this idea to an example of quotation from real life. The first thing that came to mind at that instant was the distinction between these two sentences:
Lincoln was disappointing.
"Lincoln" was disappointing.
In the former, Lincoln is a name to be evaluated. Depending on the context, it could refer to the 16th president of the United States, the capital of Nebraska, or some other object in the world. (The sentence doesn't have to be true, of course!)
In the latter, quoting Lincoln makes it a title. I intended for this "literal" reference to the word Lincoln to evoke the current feature film of that name.
Almost immediately I began to second-guess my example. The quoted Lincoln is still a name for something -- a film, or a boo, or some such -- and so still needs to be "dereferenced" to retrieve the object signified. It's just that we treat titles differently than other names.
So it's close to what I wanted to convey, but it could mislead students in a dangerous way.
The canonical real-world example of quotation is to quote a word so that we treat the utterance as the word itself. Consider:
Creativity is overused.
"Creativity" is overused.
In the former, creativity is a name to be evaluated. It signifies an abstract concept, a bundle of ideas revolving around creation, originality, art, and ingenuity. We might say creativity is overused in a context where people should be following the rules but are instead blazing their own trails.
In the latter, the quoted creativity signifies the word itself, taken literally. We might say "creativity" is overused to suggest an author improve a piece of writing by choosing a near-synonym such as "cleverness" or "originality", or by rephrasing a sentence so that the abstract concept is recast as the verb in an active statement.
This example stays more faithful to the use of quote in Scheme, where an expression is taken literally, with no evaluation of of any kind needed.
I like giving examples of how programming concepts exist in other parts of our lives and world. Even when they are not perfect matches, they can sometimes help a student's mind click on the idea as it works in a programming language or style.
I like it better when I use better examples!
My wife has been on a long-term substitute teaching assignment for the last few weeks. Yesterday, I ran across the following rubric used by one of the middle school teachers there to grade "scored discussions". The class reads a book, which they discuss as a group. Students are evaluated by their contribution to the discussion, including their observable behavior.
- Uses positive body language and eye contact (5)
- Makes a relevant comment (1)
- Offers supporting evidence (2)
- Uses an analogy (3)
- Asks a clarifying question (2)
- Listens actively -- rephrases comment before responding (3)
- Uses good speaking skills -- clear speech, loud enough, not too fast (2)
- Not paying attention (-2)
- Interrupting (-3)
- Irrelevant comment (-2)
- Monopolizing (-3)
Most adults, including faculty, should be glad that their behavior is not graded according to this standard. I daresay that many of us would leave meetings with a negative score more often that we would like to admit.
I think I'll use this rubric to monitor my own behavior at the next meeting on my calendar.
Engelbart's Violin tells the interesting story of Douglas Engelbart's chorded keyboard, or "chorder", an input device intended as a supplement to the traditional keyboard. Engelbart was part of a generation that saw computing as a universe of unlimited possibilities, and more than many others he showed us glimpses of what it could be.
I grew up in an age when an unadorned BASIC interpreter was standard equipment on any computer, and with so little software available to us, we all wrote programs to make the machine do our bidding. In a narrower way, we felt the sense of unlimited possibilities that drove Engelbart, Sutherland, and the generations that came before us. If only we all had vision as deep.
Engelbart's Violin uses strong language to judge the current state of computing, with some of its strongest lamenting the "cruel discrepancy" between the experience of a creative child learning to program and the world of professional programming:
When you are a teenager, alone with a (programmable) computer, the universe is alive with infinite possibilities. You are a god. Master of all you survey. Then you go to school, major in "Computer Science", graduate -- and off to the salt mines with you, where you will stitch silk purses out of sow's ears in some braindead language, building on the braindead systems created by your predecessors, for the rest of your working life. There will be little room for serious, deep creativity. You will be constrained by the will of your master (whether the proverbial "pointy-haired boss", or lemming-hordes of fickle startup customers) and by the limitations of the many poorly-designed systems you will use once you no longer have an unconstrained choice of task and medium.
Ouch. We who teach CS at the university find ourselves trapped between the needs of a world that employs most of our graduates and the beauty that computing offers. Alas, what Alan Kay said about Engelbart applies more broadly: "Engelbart, for better or for worse, was trying to make a violin.... [M]ost people don't want to learn the violin." I'm heartened to see so many people, including my own colleagues, working so hard to bring the ethos and joy of programming back to children, using Scratch, media computation, and web programming.
This week, I began a journey with thirty or so undergraduate CS students, who over the next four months will learn Scheme and -- I hope -- get a glimpse of the infinite possibilities that extend beyond their first jobs, or even their last. At the very least, I hope I don't shut any more doors on them.
PHOTO. The PARC 5-key Chord Keyboard, from the Buxton collection at Microsoft Research.
At the 1978 APL Conference, Alan Perlis gave a talk called Almost Perfect Artifacts Improve only in Small Ways, in which he said:
What attracted me, then, to APL was a feeling that perhaps through APL one might begin to acquire some of the dimensions in programming that we revere in natural language -- some of the pleasures of composition; of saying things elegantly; of being brief, poetic, artistic, that makes our natural languages so precious to us. That aspect of programming was one that I've long been interested in but have never found any lever for coming close to in my experience with languages of the FORTRAN, ALGOL, PL/I school.
I learned APL as as an undergrad and knew immediately that thinking in it was unlike thinking in any other language I had learned, even Lisp. These languages, though, shared a Wow! factor. They enabled programs that did amazing things, or ordinary things in amazing ways. By contrast, BASIC and FORTRAN and PL/I seemed so prosaic.
As an undergrad, I never developed the sort of fluency in that would allow me to, say, write an assembler in 20 lines of APL or Lisp. I did develop a fondness for functional programming that stayed with me into graduate school, where I came into deeper contact with Lisp. I also learned Smalltalk, which I came to admire in a way similar to Perlis's feeling for APL.
I must admit, the beauty and expressiveness of array languages and functional languages have always felt less natural to me than natural language. Their more mathematical orientation felt foreign to me, less like writing in a natural language than solving a puzzle. This wasn't a matter of me not liking math; I took advanced math throughout school and always enjoyed. But it felt different to me. This is, I see now, a personal preference and likely an indicator of why I was drawn more intimately into computer science than into more study of math.
The language I use these days that makes me feel the way Perlis feels about APL is Ruby. It occupies a similar space as Python, which we teach our students and use in several courses. I like Python a lot, more than I like most languages, but it feels plain to me in the sense once explained by John Cook. It is simple, and I get things done when I program in it, but when I use it, I feel like I am programming.
Ruby has this goofy, complex syntax that makes it possible to write some hideous stuff. But Ruby also makes it possible to write code that is brief and elegant, even artistic.
I first saw this at PLoP many years ago, when looking over Gerard Meszaros's shoulder at code he had written to support the writing and publishing of his XUnit Test Patterns book. His code read like the book he was writing. Then I began to see DSLs embedded in Ruby, tools like Rake and Treetop, that made me forget about the language they were implemented in. When you use those tools and others like them, you were writing in a new language, one that fit the thoughts in your head. Yet you were still unmistakably writing Ruby.
Perhaps if I were more an engineer at heart, I would feel differently about simple, sturdy languages that let me get things done. I like them, but they don't make me feel like I am "under the influence", as Perlis writes. They are just attractive tools. Perhaps if I were more a mathematician at heart, I would feel even more at home with the elegance that Haskell and APL give me.
Whatever the reasons, Smalltalk and Ruby grabbed in ways that no other languages have. I think that is due at least in part to the way they connected to my personal understanding and love for natural language. It's interesting how we can all feel this way about different programming languages. I think it says something important about the nature of computing and programming.
One of the barriers to learning that Dan Heisman sees in chessplayers is finding the patience to play slower. When playing any game, a person has to play slow enough to discern the consequences of moves. The chess world is complicated by the fact that games in tournament settings are timed, with a limit on the time a player can take for a certain number of moves. Over-the-board chess is played at a varieties of time limit, historically ranging from five minutes for the entire game (lightning chess) to forty moves in two and a half hours (world championship matches). Different time controls lead to different kinds of game.
Improvement at "serious" chess -- slow chess -- requires playing slower, at longer time controls. You have to practice thinking about moves and plans at a deeper level. Just as we have to train our bodies to run long distances, we have to train our chess brains to work at longer time controls.
This requires both stamina and patience. Sometimes, our brains are capable of thinking for long periods about a position, but our psyche wants to push, move faster. The barrier here is impatience "in the small", at scale of an individual game.
We see the same thing in novice programmers, who think they should be able to write a complicated program as quickly as they read a web comic or watch a YouTube video. Read the problem description; write the code. One of the important parts of most introductory programming courses is helping students learn patience at the level of writing a single program.
Another important kind of patience plays a role in the large, at learning scale. Some people want to get good fast: learn some syntax, write a few programs, and -- bam! -- be an expert. Peter Norvig has written the canonical treatment of long-term patience in learning to program.
Of course, some talented people do get good fast, or at least they seem to become good faster than we do. That can be frustrating, especially when we are struggling. But that fact is, most of us have to take time to get good at anything.
Even the most accomplished artists know that. I'm reminded of this comment from Bill Evans, one of the greatest jazz pianists of the second half of the 20th century, in The Universal Mind of Bill Evans:
"Most people just don't realize the immensity of the problem," Evans says, "and either because they can't conquer immediately they think they haven't got the ability, or they're so impatient to conquer it that they never do see it through. But if you do understand the problem, then I think you can enjoy your whole trip through."
Learning to write software well is an immense task. The most successful programmers recognize this early and enjoy the trip. This kind of patience, over the long term, makes it a lot easier to take on the barriers that inevitably appear along the way.
PHOTO. Jazz pianist Bill Evans with Miles Davis, courtesy Photos of musicians at Tumblr.
Or: What a CS Student -- or Teacher -- Can Learn from a Chess Coach
All teachers, whatever their discipline, encounter many of the same challenges. Chess coach Dan Heisman once wrote an instructive article called Breaking Down Barriers in which he discussed a split that he saw among his students:
I once wrote a short entry, Some People Get Stuff Done, about a similar phenomenon I have noticed over many years of teaching: some students find a way to get things done: to write the program, to solve the problem, to pass the course. These are usually the same students who find -- and make -- ways to get better at their craft. When they encounter barriers to their learning, they find a way to go over, around, or through them.
These are also the students who tend to succeed after they graduate and leave the shelter of a school system that often does more to help them succeed than they realize. The business world isn't always so forgiving.
The starting point for students who break down barriers to learning is a particular mindset, an attitude that they can learn. This is the mindset that enables these students to persevere when they encounter a roadblock. In some students, this attitude seems to encourage them to persevere.
A positive attitude isn't sufficient on its own. Believing that you can defeat a better player over the chessboard doesn't mean you will. You still have to do it. But, as Heisman says, a defeatist attitude can be a self-fulfilling prophecy during a game.
The same is true for learning computer science, or any other academic discipline. Positive attitude isn't the endpoint. It is the starting line. It is what allows you to continue working when things get difficult. The hard work is what gets you over, around, or through the barriers.
The good news is that hard work is more important than innate ability. Dick Gabriel is fond of saying that talent doesn't determine how good you get; it determines how fast you get good. How hard you work determines how good you get.
So, the right mindset is useful, and working hard is essential. But even these are not enough. Doing the right kind of work is essential. Students who don't realize this can demotivate themselves quickly. They throw themselves into their work, spend a lot of time and energy doing counterproductive things... and don't get better. They figure they "don't have what it takes" and move on to something else.
As a teacher, few things make me sadder than to see a student who wants to learn and is willing to work burn him- or herself out by spinning wheels with unhelpful, unproductive, uninformed study. When these students are in my class, I wonder, "Why didn't they come get help?" Or, if they did, "Why didn't they follow my advice?"
Some practices support learning better than others. There is a skill to learning, a discipline and a way of working that succeeds better than others. Often, the students do best in my courses are not the most gifted students but rather the ones who have learned how to attend class, how to read, and how to study. Many of these students figured out these skills early on in their school careers, or got lucky. It doesn't matter which. In any case, these skills are multipliers that enable these students to accelerate in every course they take. Knowledge and skill accumulate, and pretty soon these students look like something apart from their struggling colleagues.
But they aren't. They are doing things any student can do. "But I'll never catch up to those students, no matter how hard I work." Maybe, and maybe not. That doesn't matter, either. This is about your learning. You have to start from where you are, and go forward from there.
A good teacher or coach really can help students, by helping them get over incidental barriers and helping them learn how to get over the essential barriers in a productive way. One of the most important things a teacher can do is to provide feedback loops of both short and long duration, and then help students identify mistakes and minimize their repetition. This is obviously invaluable in playing chess, where pattern recognition and speed are fundamental capabilities. But pattern recognition and speed are fundamental capabilities in any kind of learning.
Some people these days like to downplay the importance of a human teacher or coach in learning to develop software. "We have the compiler, which gives us all the feedback we need any time of day." Yes, indeed. We have access to tools that our predecessor could only have dreamed of, and these tools empower us as learners. But are they always enough?
Chess players have something akin to our compiler: the chess computer. When I got my first chess computer in high school, I was ecstatic. I could play any time, anywhere, against a player that could be set to any level from beatable novice to untouchable master. I played a lot of games. A lot. And I learned a lot, too, as I did any time I played a lot of games and thought about them. But there were times when I didn't understand why something worked, or didn't. In those cases, I consulted the writings of a good teacher, or asked a human coach for some help. They helped me get over the obstacle faster than I could on my own.
That's another role that our teachers can play: they can help us to understand why.
In his article, Heisman talks about some of the common barriers that chess students face and how to overcome them. Some seem specific to the game or competitive activities, but remarkably all of them apply equally well to students of computing or software development.
The major difference is that the barriers outlined are ones encountered by people who do most of their learning on their own, not in the classroom. Chess players don't usually go to school full time. If they have a teacher at all, it's more like piano lessons than a university program. The student meets with the teacher once a week (or less) and then studies, practices, and plays a lot in between sessions.
A lot of people these days believe that learning to create software is or should be more like this model than the university model, too. Movements like Software Apprenticeship and Codecademy are all about enabling individuals to take control of their own learning. But even in a university setting, learning works best when students study, practice, and program a lot in between class sessions or meetings with the professor.
Heisman discusses ten barriers. See if you can map them onto learning CS, or how to write software:
It's not that hard, is it? ("Some players unfriendly on the internet"? We invented that one!)
A few of these stand out in my experience as a teacher and student. Consider #2. Chess players have ratings that reflect the level of their play. When you perform better than expected at a tournament, your rating goes up. When you perform poorer than expected, your rating goes down.
In the university, this corresponds to grades and grade-point average. Some students are paralyzed by the idea that their GPA might go down. So they take easier courses, or seek out professors who don't grade as hard as others. The negative outcome of this approach is that the courses don't challenge the student enough, and it is the challenge that pushes them to learn. Protecting your GPA in this way can cause you to learn less.
Ironically, this barrier most often affects students who have historically done well in school. They are the ones used to having high GPAs, and too often they have invested way too much of their self-worth in their grades. Students who expect to do well and to have "ratings" that confirm their status face an extra psychological barrier when the material becomes more challenging. This is one of those situations in which another person -- even a teacher! -- can be of enormous value by providing emotional support.
Homework isn't fun is a universal barrier to learning. There are many strategies for trying to get through the drudgery of work, and a good teacher tries them all. But, in the end, it is work. You just have to get over it. The good news is that there is a self-reinforcing cycle between doing the work and enjoying the work. Hugh MacLeod captures it well:
Hard work is also scary. We might fail. But if we keep working, eventually we can succeed. What can keep us from doing the work?
Time is a limiting factor. Students often tell me, "I don't have the time..." to study, or write more code, or come in to get help. This can be a real challenge for students who have to work thirty hours a week to pay the bills, or who have families to care for.
I ask my students to be honest with themselves. Do you not have the time, or do you not make the time? Sometimes it's bad habit, frittering away time at video games or socializing. Sometimes it's bad habit that uses time inefficiently or ineffectively. These are habits you can change -- if you want to.
A student came to me just after we took our midterm exam last semester. He had done poorly and was worried about his grade. He asked if there was any chance left that he could succeed in the course. I said "yes", contingent on the answer to this question: What are you willing to change in your life to make success possible? Clearly, what he was doing wasn't enough. Either he was not devoting enough time to the course, or he was putting in enough time but not doing the right things. Was he willing to change what needed to be changed, if only for the eight weeks left in the course? He was honest with himself and dropped the course. A couple of other students made changes to how they worked on the course and recovered quite nicely.
Ultimately, if you want to succeed at something, you make time to do the work.
Twenty-five years ago, Rolling Stone panned the re-release of rocker John Mellencamp's debut album, Chestnut Street Incident. In the ten years since its original release, Mellencamp had become a star. His work in the intervening years made the quality of his debut look all the worse. It was cocky and klutzy, less than the sum of his musical influences. "Back then," the reviewer wrote, Mellencamp's "ambition definitely exceeded his grasp". The album wasn't very good, and the review said so, harshly.
Mellencamp wouldn't have disagreed. In interviews, he has often talked about how bad a songwriter he was when he first started in the business. On top of that, he faced obstacles similar to those facing many other young artists, including promoters and handlers more interested in music industry fashion and short-term profit than art. They even made him take a stage name, "Johnny Cougar", in the interest of marketability.
But he didn't settle for his initial condition. He continued to learn, honing his songwriting skills and learning to manage his own affairs. Along the way, he learned the sort of humility that many artists confident in their art have. Eventually, his grasp matched his ambition. He succeeded commercially and achieved a small measure of critical acceptance.
I must say that I have always liked Chestnut Street Incident, in part for its raw, desperate ambition. Here was a kid from small-town Indiana who wanted to grow beyond his roots and become something more. The lyrics are not profound, and the emotion is not complicated. I've always admired Mellencamp for his attitude about work and craft, and his willingness to try and to fail.
To learn is to break down barriers. Whether you are learning to play chess or to write software, you will encounter obstacles. Breaking them down is a matter of mindset, effort, and specific skills -- all of which are within reach.
Even if you aren't a chess player, you may well enjoy reading Heisman's article. CS students and teachers alike can benefit from its lessons.
My workout at dawn this New Year's Day brought me the following passage, from Dave Winer:
... it gets ridiculous near the end, time runs so fast, it's December just after it's January and then of course it's January again, until there's no more time.
Time goes by quickly, whether we use it well or not. We may as well use the time we have to its fullest, until there's no more time.
I spent part of my morning playing at the intersection of today and yesterday. My wife gave me a USB-equipped turntable for Christmas, which will be handy for converting some music I have on vinyl LPs to digital format. With so much music streaming on the internet these days, it's hard to believe that there is anything not available on CD or iTunes. Even when a remastered CD is available, though, sometimes it's more fun to spin the vinyl record, convert it to something more "modern", and fiddle with the resulting file to get just the right sound.
May the blink of an eye that is 2013 bring you manifold opportunities to build things and tear them down, and may you have a lot of fun along the way.