Telescopes, awk, and learning

Here’s a quote I think about often:

“It is faster to make a four-inch mirror and then a six-inch mirror than to make a six-inch mirror.” — Bill McKeenan, Thompson’s law of telescopes

If your goal is to make a six-inch mirror, why make a four-inch mirror first? From a reductionist perspective this makes no sense. But when you take into account how people learn, it makes perfect sense. The bigger project is more likely to succeed after you learn more about mirror-making in the context of a smaller project.


I was thrilled to discover the awk programming language in college. Munging files with little awk scripts was at least ten times easier than writing C programs.

When I told a friend about awk, he said “Have you seen Perl? It’ll do everything awk does and a lot more.”

If you want to learn Perl, I expect it would be faster to learn awk and then Perl than to learn Perl. I think I would have been intimidated by Perl if I’d tried to learn it first. But thinking of Perl as a more powerful awk made me more willing to try it. Awk make my life easier, and Perl had the potential to make it even easier. I’m not sure whether learning Perl was a good idea—that’s a discussion for another time—but I did.


I also learned C before learning C++. That was beneficial for similar reasons, starting with the four-inch mirror version of C++ before going on to the six-inch version.

Many people have said that learning C before C++ is a bad idea, that it teaches bad habits, and that it would be better to learn (modern) C++ from the beginning. That depends on what the realistic alternative is. Maybe if you attempted to learn C++ first you’d be intimidated and give up. As with giving up on learning Perl, giving up on learning C++ might be a good idea. At the time, however, learning C++ was a good move. Knowing C++ served me well when I left academia.

Learning on your own

Teaching yourself something requires different tactics than learning something in a classroom. The four-inch mirror warmup is more important when you’re learning on your own.

If I were teaching a course on C++, I would not teach C first. The added structure of a classroom makes it easier to learn C++ directly. The instructor can pace students through the material so as to avoid the intimidation they might face if they were attempting to learn C++ alone. Students don’t become overwhelmed and give up because they have the accountability of homework assignments etc. Of course some students will give up, but more would give up without the structure of a class.

Top-down vs bottom-up

From a strictly logical perspective, it’s most efficient to learn the most abstract version of a theorem first. But this is bad pedagogy. The people who are excited about the efficiency of compressing math this way, e.g. Bourbaki, learned what they know more concretely and incrementally, and think in hindsight that the process could be shortened.

It does save time to present things at some level of generality. However, the number of steps you can go up the abstraction ladder at a time varies by person. Some people might need to go one rung at a time, some could go two at a time or maybe three, but everyone has a limit. And you can take bigger steps when you have a teacher, or even better a tutor, to guide you and to rescue you if you try to take too big of a step.

You typically understand something better, and are more able to apply it, when you learn it bottom-up. People think they can specialize more easily than they can generalize, but the opposite is usually true. It’s easier to generalize from a few specific examples than to realize that a particular problem is an instance of a general pattern.

I’ve noticed this personally, and I’ve noticed it in other people. On Twitter, for example, I sometimes post a general and a concrete version of a theorem, and the more concrete version gets more engagement. The response to a general theorem may be “Ho hum. Everybody knows that.” but the response to a particular application may be “Wow, I never thought of that!” even when the latter is a trivial consequence of the former.

Related posts

9 thoughts on “Telescopes, awk, and learning

  1. Going from Awk to Perl is also aided by the existence of the “a2p” tool, which translates an Awk program to a Perl program. It feels like magic—and more to the point, if you have a good understanding of Awk, you can run your programs through the tool to see at least one way you could do the same thing in Perl.

  2. I try to ‘teach by example’ or ‘teach by problem’. I will sometimes state the general principle, but I will always go into practice, as soon as possible.

  3. Yes… if specialization were easier than generalization, then we should teach elementary school kids category theory instead of arithmetic.

    So many of the “What really is a monad?” blog posts on the net have the same problem Bourbaki has. Someone learned them through example after example and then thought, “if only people could understand the general case before ever seeing an example, it would make so much more sense”. (Spoiler alert: it doesn’t.)

  4. As a C++ programmer who started with C, I think the debate as to whether learning C first instills bad habits or whether it’s a valuable experience hinges entirely on what the end goal is.

    If your end goal is to be a C++ programmer, starting with C is a terrible idea. I don’t think I would say that it actually teaches bad habits, it just teaches non-C++ ways to do things. Modern C++ is so far removed from C that it’s almost absurd, and the fact that C++ compilers accept C code is, to a C++ programmer, sort of like how a C programmer might view a function implemented via inline assembly. Sure, it’s nice that the facility exists, but using it often will not endear you to your fellow programmers.

    However, if your end goal is to learn how to program computers, learning C first is a fantastic move. Learning C and then transitioning to C++ allows you to view the functioning of a higher-level language through the lens of a lower-level language.

    I still get told that I write my C++ code “like a C programmer”. But I wouldn’t have it any other way. I believe I write my code like someone who knows what each of the higher-level abstractions is actually doing and is optimizing them as I go.

  5. Learning C first wasn’t a bad idea in the 1990s, but it gets harder to justify over time. I don’t know now whether C would even provide that much of an onramp for contemporary C++.

    I wrote a lot of C++ at one time, and found it hard to go back to writing C when I had to. Now I’m more likely to write C than C++. I suppose it’s because clients come to me with numerical algorithms rather than application code.

  6. Logical approach, typically I want to learn X, so dive into it immediately? Not an easy generalisation.
    Thank you

  7. Not surprised to see monads already mentioned – they are probably the best example I’ve seen of this phenomenon.

    But the thing to realize about all those “What is a monad?” articles out there is that they are written to allow the author to solidify their understanding, not for others to use. One does not truly understand monads until one has come up with their own wacky analogy for them. (Mine involves passing your carry-on luggage through airport security. I have not inflicted it upon the general public, as a courtesy. )

  8. Oh, and your first quote seems related to the common software principle: “Build one to throw away”, or “Plan on replacing the first version”.

    It probably doesn’t hurt to have a extra four-inch telescope laying around, but deploying and supporting a second version of a program can be a big cost, so IT just tosses the first attempt.

  9. I too learned AWK before Perl. I still use AWK. I try to avoid Perl (as a goal for at least the last 15 years). Thing is, Perl was brilliant when running on a single CPU, and when Unix (now Linux) program load times were significant. (Windows/DOS program load times were miserable.) In the late-1980s/early-1990s, our deployed systems did not have space for Perl, so I was mostly stuck writing shell scripts and AWK/grep/sed. Perl was brilliant then, as a single program-load could do it all. But even then I wondered if a simple pipelined shell script using AWK might be faster when we had multiple CPUs – as is now normal.

    Perl was a largely a solution to a problem that no longer exists. Also, AWK has improved. My old-style script pipelines are likely more performant than Perl. Perl has become a dead-end.

    If you need to write hyper-optimized bare-metal efficient code, then you should learn C/C++ and maybe a bit of assembly. Your average programmer is not going to write dangerous code, on anything substantial. Should this be taught? Maybe, but with limited expectations.

    C++ is also partly a dead-end. You can use the “C with classes” subset of C++ as a better version of C (where C is sometimes called a high-level assembler). You might use “modern C++”, which tries to be more like Java. … but in that case use Java (or C#, or the like). At base, C++ still has all the hazards of C (and assembly) for the unwary programmer.

    C++ fits with the old Dr Dobbs magazine mantra. :)

    In the present, my preferred general-purpose tool is Javascript, as offered by “node” (or sometimes “nodejs”). Node is Javascript with asynchronous processing and networking as the base, built on a hideously efficient engine.

    Come to think of it, I would *strongly* recommend teaching Javascript – first directly in a web browser, and then introducing more advanced concepts, using both client-side browser, and server-side nodejs.

    (Oh. If you have any Javascript books from early 2000s or before, *burn them*. None of the early books I saw understood the potential of the language.)

    I agree about the simple/concrete to general sequence, but would factor things a little differently.

Comments are closed.