(This is a snapshot of my old weblog. New posts and selected republished essays can be found at raganwald.com.)

Thursday, October 18, 2007
  The challenge of teaching yourself a programming language

Programming as a profession requires a great deal of learning on one’s own. Whether you think Universities should or should not be in the business of providing job training for software development, the fact is that the industry moves far too rapidly for Universities to teach more than a small portion of the knowledge required to be competent on the job, even at an entry level.

Teaching oneself involves more than just reading a book and playing around, sometimes it involves taking time to investigate the parts that don’t immediately make sense. (Note that those steps are the shortest, simplest path from confusion to understanding; it might take someone more work than that, but the fact remains that there is a simple and reasonable path to understanding and that it isn’t particularly hard to find.) If one does not know how to learn on one’s own, self-teaching is the wrong choice…
—Gregory, The Magic in the Box

You have to take responsibility for teaching yourself, and that is a far greater responsibility than skimming a book and fooling around copying and pasting code from web pages. You can’t just take basic or even sketchy knowledge of how to program in one language and “transfer” it to another language. You think you can just “pick it up,” but in reality you can’t, and neither can I. Even Peter Norvig needs ten years to learn a new language.

Essentials of Programming Languages introduces programming languages in one of the strongest ways possible: by building a simple interpreter for each language concept (The “P.J. Plauger” method). There are other important ways to learn a programming language, but none will teach you as much about how language features actually work.

Returning to the quote, there is a temptation to think of learning a new language or system in terms of your facility with problems you set for yourself. Meaning, you pick up a new language and immediately try to perform some task with it. A task you choose. And you probably have a preconceived idea of how to go about solving the task. And when you have successfully performed that task, you think you have learned the language.

When put this way, it is obviously nonsensical. It is like writing a test where you choose the questions.

But this type of thinking leads to skirting around or avoiding anything confusing or “difficult.” This type of thinking avoids anything truly new and different in favour of using the new language as closely as possible to how you use your existing languages. And that means that you really haven’t learned anything worthwhile, just some new syntax.

To truly learn a new language, you have to learn the different things. When you find something difficult, something that doesn’t make sense, you don’t avoid it, you embrace it. This is where the actual learning takes place. For example, it is possible—even easy—to write Ruby programs that do not use blocks. They work just like Java programs. But of course, such a program isn’t really a Ruby program in any substantial sense. If you were to avoid blocks because (a) they look weird, and (b) you can write your program without them, in what sense have you learned how to program in Ruby?

Types and Programming Languages will introduce you to programming languages in a fascinating way: by examining the different type systems behind them.

Imagine yourself as a master carpenter who is training an aspiring apprentice. The apprentice has assembled some Ikea furniture and decided he likes carpentry, so he’s going to give it a whirl. One day, he brings in a stool with a leg that needs replacing. He says, “I’ve been trying to remove the leg, but the screw is just stuck or something, and I think something is wrong with it.” You look, and ask him to show you how he’s tried to go about it. He picks up a screwdriver and desperately tries to fit its flat head into the cross of the phillips screw. You tell him to stop, take out a phillips screwdriver, and proceed to unscrew things easily. He gawks and asks, “There are different kinds of screws that need to be treated differently?”

Imagine your horror. How could he not know something so basic? Aspiring to be a carpenter requires understanding the tools a carpenter uses. Likewise, aspiring to be a programmer requires understanding the tools a programmer uses. [ibid]

When learning a new language or tool, do not shy away from things that seem different, weird, confusing, counter-intuitive, or unfamiliar. Do not put them off because you can work around them. Learn them, try them, and persist with them until you discover why they make sense. This is the true road to teaching yourself a new language. And in today’s fast-moving industry, it’s a road we all share.

Comments on “The challenge of teaching yourself a programming language:

Norvig writes "Teach Yourself Programming in Ten Years", not "Teach Yourself [some specific language] in Ten Years".
I like your Java Ruby example. A big problem of programming Ruby in a Java like fashion is that the programmer will have immense difficulty understanding any source code or example code from the core Ruby library or key 3rd party libraries. And without being able to leverage that, your output would be fairly poor.
Norvig talks about programming, yes, but still there are differences in languages that take a considerable amount of time to re-learn. Haskell is so strange to us imperial programmers that I'm still not even beginning to get it.
Every new languages I've learned was to solve a particular problem. PHP makes web programming easy, Perl is good for text, etc. Here's the thing: I'd like to learn either a functional language or a lisp variant. The problem is that so far, I haven't found any problem that I can solve efficiently with them that I cannot do with c, c++, java, perl, python, php, shell scripts, etc. I suspect a lot of people are like me in this respect and find that the best way to learn a language is to solve a problem that would be too difficult (or too time-consumming) to do in other languages.

Any advice for people like me? Or are we going at it totally wrong?
I agree with you dfd. The easiest way for me to learn (or at least "pick up") a new language is to take a problem and try to solve it.
Of course I wouldn't claim to be an expert or even an advanced coder of that language after only one project, but I would definitely have learned enough of it to be able to tackle more problems with it.
I would say you can learn a language by taking on a project in it, and depending on the complexity of the project and how much you try to learn the specific features of the language will correlate with how much of the language you actually learn. It's basically up to you how much of the language you want to learn, by how much of the language you are willing to explore.
what about plauger's method?

"My approach to learning a programming language is to write a compiler for it." p.j. plauger
I think it's really important to read good code by experts in the language. That'll teach you the true power and idioms of the language, so you don't keep coding "ruby in Java" or whatever combination :)
my own experience has been that the hardest part about learning a language is finding good exercises to do with it. i'll break open an interpreter and pass some messages around or twiddle with a graphics library, but finding meaningful practice routines when i'm trying to immerse myself in a language, that is often far harder than implementing the routine.
I followed the advice in the pragmatic programmers books of learning a new language every year, I've actually learned more than one every year, but in the spirit of your article, I'd rather say that it's not the new syntax that I'm looking for, but the new paradigm, or the exceptional part in every language that makes it particular.
Sometimes, you open a door into a completely new world.
For example I've never heard of Haskell a year before, and discovering this language was like opening "la boite de pandore". I found my self digging into things like type theory, categories, proofs, semantics, combinatory logic, and I'm actually reading MacLanes's Algebra. I've been always working in "Enterprise Software", and I can't say that I'm using the knowledge I'm gathering by following the path of every new paradigm I learn in each new language, I'd rather not talk about it in my working environment to avoid the label of the weird guy, but what I'm learning is evidently making me a better programmer, a better problem solver.

Other languages which I find interesting : Scala(pi and join calculus, Actors, FP and OOP, mixins, pattern matching, type inference, closures, DSL, implicit defs , type constructors ..) , Perl 6 ( hyper operators, junctions, first class Grammars, .. ), Oz (dataflow, + many things from the above ..)
programming's goal is simplification of problem, language is just a mean

what one needs is a language so flexible it can emulate other language's features/techniques ... at programmer's will ... at any time

it's not important to learn *every* language or even a subset of it - or even *gasp* dissect it

we all need that time wasted on relearning things in different ways ... and apply it to our true goal:simplification
This is the first time in almost 2 years of reading your blog that I've felt the drive to comment. :)

I prefer to distinguish "learning" a language from "mastering" it -- primarily to disempower people who insist that they "cannot learn to program".

Learning to program, in any language, is not much different from learning to drive or learning to cook; there are shades of success. Could any one of us go out today and win a NASCAR (or similar) event? Would we pass muster as Head Chef in one of Gordon Ramsey's restaurant? Probably not.

"First, you need to learn to think. That's going to be the hard part. Once you know how to think, you only need to spend a short while with any language to learn the syntax, and you can program in that language. It's that first one that trips everyone up."
Ancient one:

I accept it may not take ten years to "merely" learn to program. Learning had better be less than mastery: if they are the same thing, I haven't learned to program yet.

But w.r.t. my argument, you cannot ride a bicycle, then climb into a car and figure out how to drive on your own after playing around in a parking lot.

Sure, you grasp the differences from a bicycle in terms of steering, accelerating, and braking.

But to be able to drive in traffic you are going to need to learn a set of skills that are different than a bicycle, such as how blind spots work, the different braking behaviour, under- and -oversteering, drift when you take your hands off the wheel, and so forth.

These are not obvious if you simply try to translate your bicycle skills to driving an automobile.

I think your suggestion that learning is less than mastering is apt, but nevertheless it is far more than figuring out how to do something that is well within your comfort zone.
I've had a similar experience to dfd. Each language and development tool has a particular strength and reason for being. I get by doing most of my personal work in Rebol ( http://musiclessonz.com/rebol_tutorial.html ), but a little PHP can often help with web site scripts, a little VB and an existing Com component can provide a simple solution to a complex desktop problem, Python on my pocket PC provides a great toolbox for lots of useful little data processing tasks. I've always been compelled to learn new tools that are right for the job, just because there's a need for an effective solution. Every language is an abstraction layer, built upon other layers of abstraction. You use HTML, Javascript, etc. to build web sites because the web browser is the environment in which that level of abstraction occurs. There's no place for assembly code in that environment. Likewise, device drivers may be written in assembly, and there's no place for a scripting language at that level. I think that's how language learning should be presented: here are the available tools, these are their strengths and weaknesses, and here's why each specific tool is used for a given need, in a given environment.
To follow up my original comment on "what are good problems to try on new languages," I repeated this question in programming.reddit.com and got two helpful answers:
Rosetta Code
Project Euler

Both of these sites have problems to help you learn programming language.

<< Home
Reg Braithwaite

Recent Writing
Homoiconic Technical Writing / raganwald.posterous.com

What I‘ve Learned From Failure / Kestrels, Quirky Birds, and Hopeless Egocentricity

rewrite_rails / andand / unfold.rb / string_to_proc.rb / dsl_and_let.rb / comprehension.rb / lazy_lists.rb

IS-STRICTLY-EQUIVALENT-TO-A / Spaghetti-Western Coding / Golf is a good program spoiled / Programming conventions as signals / Not all functions should be object methods

The Not So Big Software Design / Writing programs for people to read / Why Why Functional Programming Matters Matters / But Y would I want to do a thing like this?

The single most important thing you must do to improve your programming career / The Naïve Approach to Hiring People / No Disrespect / Take control of your interview / Three tips for getting a job through a recruiter / My favourite interview question

Exception Handling in Software Development / What if powerful languages and idioms only work for small teams? / Bricks / Which theory fits the evidence? / Still failing, still learning / What I’ve learned from failure

The unary ampersand in Ruby / (1..100).inject(&:+) / The challenge of teaching yourself a programming language / The significance of the meta-circular interpreter / Block-Structured Javascript / Haskell, Ruby and Infinity / Closures and Higher-Order Functions

Why Apple is more expensive than Amazon / Why we are the biggest obstacles to our own growth / Is software the documentation of business process mistakes? / We have lost control of the apparatus / What I’ve Learned From Sales I, II, III

The Narcissism of Small Code Differences / Billy Martin’s Technique for Managing his Manager / Three stories about The Tao / Programming Language Stories / Why You Need a Degree to Work For BigCo

06/04 / 07/04 / 08/04 / 09/04 / 10/04 / 11/04 / 12/04 / 01/05 / 02/05 / 03/05 / 04/05 / 06/05 / 07/05 / 08/05 / 09/05 / 10/05 / 11/05 / 01/06 / 02/06 / 03/06 / 04/06 / 05/06 / 06/06 / 07/06 / 08/06 / 09/06 / 10/06 / 11/06 / 12/06 / 01/07 / 02/07 / 03/07 / 04/07 / 05/07 / 06/07 / 07/07 / 08/07 / 09/07 / 10/07 / 11/07 / 12/07 / 01/08 / 02/08 / 03/08 / 04/08 / 05/08 / 06/08 / 07/08 /