Hackers and Painters - Big Ideas from the Computer Age

Chapter 10. Programming Languages Explained.

There are two kinds of symmetry, repet.i.tion and recursion. Recursion means repet.i.tion in subelements, like the pattern of veins in a leaf.

Symmetry is unfashionable in some fields now, in reaction to excesses in the past. Architects started consciously making buildings asymmetric in Victorian times, and by the 1920s asymmetry was an explicit premise of modernist architecture. Even these buildings only tended to be asymmetric about major axes, though; there were hundreds of minor symmetries.

In writing you find symmetry at every level, from the phrases in a sentence to the plot of a novel. You find the same in music and art. Mosaics (and some Cezannes) have extra visual punch because the whole picture is made out of the same atoms. Compositional symmetry yields some of the most memorable paintings, especially when two halves react to one another, as in the Creation of Adam or American Gothic.

In math and engineering, recursion, especially, is a big win. Inductive proofs are wonderfully short. In software, a problem that can be solved by recursion is nearly always best solved that way. The Eiffel Tower looks striking partly because it is a recursive solution, a tower on a tower.

The danger of symmetry, and repet.i.tion especially, is that it can be used as a subst.i.tute for thought.

GOOD DESIGN RESEMBLES NATURE. It"s not so much that resembling nature is intrinsically good as that nature has had a long time to work on the problem. So it"s a good sign when your answer resembles nature"s.

Figure 9-2. Eiffel Tower, 1889. A tower on a tower.

It"s not cheating to copy. Few would deny that a story should be like life. Working from life is a valuable tool in painting too, though its role has often been misunderstood. The aim is not simply to make a record. The point of painting from life is that it gives your mind something to chew on: when your eyes are looking at something, your hand will do more interesting work.

Imitating nature also works in engineering. Boats have long had spines and ribs like an animal"s ribcage. In other cases we may have to wait for better technology. Early aircraft designers were mistaken to design aircraft that looked like birds, because they didn"t have materials or power sources light enough, or control systems sophisticated enough, for machines that flew like birds. But I could imagine little unmanned reconnaissance planes flying like birds in fifty years.

Figure 9-3. Leonardo da Vinci, study of a rearing horse, 1481-99.

Now that we have enough computer power, we can imitate nature"s method as well as its results. Genetic algorithms may let us create things too complex to design in the ordinary sense.

GOOD DESIGN IS REDESIGN. It"s rare to get things right the first time. Experts expect to throw away some early work. They plan for plans to change. It takes confidence to throw work away. You have to be able to think, there"s more where that came from. When people first start drawing, for example, they"re often reluctant to redo parts that aren"t right. They feel they"ve been lucky to get that far, and if they try to redo something, it will turn out worse. Instead they convince themselves that the drawing is not that bad, really-in fact, maybe they meant it to look that way.

Dangerous territory, that. If anything, you should cultivate dissatisfaction. In Leonardo"s drawings there are often five or six attempts to get a line right. The distinctive back of the Porsche 911 only appeared in the redesign of an awkward prototype. In Wright"s early plans for the Guggenheim, the right half was a ziggurat; he inverted it to get the present shape.

Mistakes are natural. Instead of treating them as disasters, make them easy to acknowledge and easy to fix. Leonardo more or less invented the sketch, as a way to make drawing bear a greater weight of exploration. Open source software has fewer bugs because it admits the possibility of bugs.

It helps to have a medium that makes change easy. When oil paint replaced tempera in the fifteenth century, it helped painters to deal with difficult subjects like the human figure because, unlike tempera, oil can be blended and overpainted.

GOOD DESIGN CAN COPY. Att.i.tudes to copying often make a round trip. A novice imitates without knowing it; next he tries consciously to be original; finally, he decides it"s more important to be right than original.

Unknowing imitation is almost a recipe for bad design. If you don"t know where your ideas are coming from, you"re probably imitating an imitator. Raphael so pervaded mid-nineteenth century taste that almost anyone who tried to draw was imitating him, often at several removes. It was this, more than Raphael"s own work, that bothered the Pre-Raphaelites.

The ambitious are not content to imitate. The second phase in the growth of taste is a conscious attempt at originality.

I think the greatest masters go on to achieve a kind of selflessness. They just want to get the right answer, and if part of the right answer has already been discovered by someone else, that"s no reason not to use it. They"re confident enough to take from anyone without feeling that their own vision will be lost in the process.

Figure 9-4. Lockheed SR-71, 1964.

GOOD DESIGN IS OFTEN STRANGE. Some of the very best work has an uncanny quality: Euler"s Formula, Bruegel"s Hunters in the Snow, the SR-71, Lisp. They"re not just beautiful, but strangely beautiful.

I"m not sure why. It may just be my own stupidity. A can opener must seem miraculous to a dog. Maybe if I were smart enough it would seem the most natural thing in the world that eip = -1. It is after all necessarily true.

Most of the qualities I"ve mentioned are things that can be cultivated, but I don"t think it works to cultivate strangeness. The best you can do is not squash it if it starts to appear. Einstein didn"t try to make relativity strange. He tried to make it true, and the truth turned out to be strange.

At an art school where I once studied, the students wanted most of all to develop a personal style. But if you just try to make good things, you"ll inevitably do it in a distinctive way, just as each person walks in a distinctive way. Michelangelo was not trying to paint like Michelangelo. He was just trying to paint well; he couldn"t help painting like Michelangelo.

The only style worth having is the one you can"t help. And this is especially true for strangeness. There is no shortcut to it. The Northwest Pa.s.sage that the Mannerists, the Romantics, and two generations of American high school students have searched for does not seem to exist. The only way to get there is to go through good and come out the other side.

Figure 9-5. Bruegel"s Hunters in the Snow, 1565.

GOOD DESIGN HAPPENS IN CHUNKS. The inhabitants of fifteenth century Florence included Brunelleschi, Ghiberti, Donatello, Masaccio, Filippo Lippi, Fra Angelico, Verrocchio, Botticelli, Leonardo, and Michelangelo. Milan at the time was as big as Florence. How many fifteenth century Milanese artists can you name?

Something was happening in Florence in the fifteenth century. And it can"t have been genetic, because it isn"t happening now. You have to a.s.sume that whatever inborn ability Leonardo and Michelangelo had, there were people born in Milan with just as much. What happened to the Milanese Leonardo?

There are roughly a thousand times as many people alive in the US right now as lived in Florence during the fifteenth century. A thousand Leonardos and a thousand Michel Angelos walk among us. If DNA ruled, we should be greeted daily by artistic marvels. We aren"t, and the reason is that to make Leonardo you need more than his innate ability. You also need Florence in 1450.

Nothing is more powerful than a community of talented people working on related problems. Genes count for little by comparison: being a genetic Leonardo was not enough to compensate for having been born near Milan instead of Florence. Today we move around more, but great work still comes disproportionately from a few hotspots: the Bauhaus, the Manhattan Project, The New Yorker , Lockheed"s Skunk Works, Xerox Parc.

At any given time there are a few hot topics and a few groups doing great work on them, and it"s nearly impossible to do good work yourself if you"re too far removed from one of these centers. You can push or pull these trends to some extent, but you can"t break away from them. (Maybe you can, but the Milanese Leonardo couldn"t.) GOOD DESIGN IS OFTEN DARING. At every period of history, people have believed things that were just ridiculous, and believed them so strongly that you risked ostracism or even violence by saying otherwise.

If our own time were any different, that would be remarkable. As far as I can tell it isn"t.

This problem afflicts not just every era, but in some degree every field. Much Renaissance art was in its time considered shockingly secular: according to Vasari, Botticelli repented and gave up painting, and Fra Bartolommeo and Lorenzo di Credi actually burned some of their work. Einstein"s theory of relativity offended many contemporary physicists, and was not fully accepted for decades-in France, not until the 1950s.

Today"s experimental error is tomorrow"s new theory. If you want to discover great new things, then instead of turning a blind eye to the places where conventional wisdom and truth don"t quite meet, you should pay particular attention to them.

In practice I think it"s easier to see ugliness than to imagine beauty. Most of the people who"ve made beautiful things seem to have done it by fixing something they thought ugly. Great work usually seems to happen because someone sees something and thinks, I could do better than that . Giotto saw traditional Byzantine madonnas painted according to a formula that had satisfied everyone for centuries, and to him they looked wooden and unnatural. Copernicus was so troubled by a hack that all his contemporaries could tolerate that he felt there must be a better solution.

Intolerance for ugliness is not in itself enough. You have to understand a field well before you develop a good nose for what needs fixing. You have to do your homework. But as you become expert in a field, you"ll start to hear little voices saying, What a hack! There must be a better way. Don"t ignore those voices. Cultivate them. The recipe for great work is: very exacting taste, plus the ability to gratify it.

Chapter 10. Programming Languages Explained.

Any machine has a list of things you can tell it to do. Sometimes the list is short. There are only two things I can do to my electronic kettle: turn it on and turn it off. My CD player is more complicated. As well as turning it on and off, I can turn the volume up and down, tell it to play or pause, move back or forward one song, and ask it to play songs in random order.

Like any other kind of machine, a computer has a list of things it can do. For example, every computer can be told to add two numbers. The complete list of things a computer can do is its machine language.

10.1. Machine Language

When computers were first invented, all programs had to be written as sequences of machine language instructions. Soon after, they started to be written in a slightly more convenient form called a.s.sembly language . In a.s.sembly language the list of commands is the same, but you get to use more programmer-friendly names. Instead of referring to the add instruction as 11001101, which is what the machine might call it, you get to say add.

The problem with machine/a.s.sembly language is that most computers can only do very simple things. For example, suppose you want to tell a computer to beep 10 times. There"s not likely to be a machine instruction to do something n times. So if you wanted to tell a computer to do something 10 times using actual machine instructions, you"d have to say something equivalent to: put the number 10 in memory location 0 a if location 0 is negative, go to line b beep subtract 1 from the number in location 0 go to line a b ...rest of program...

If you have to do this much work to make the machine beep 10 times, imagine the labor of writing something like a word processor or a spreadsheet.

And by the way, take another look at the program. Will it actually beep ten times? Nope, eleven. In the first line I should have said 9 instead of 10. I deliberately put a bug in our example to ill.u.s.trate an important point about languages. The more you have to say to get something done, the harder it is to see bugs.

10.2. High-Level Languages

Imagine you had to produce a.s.sembly language programs, but you had an a.s.sistant to do all the dirty work for you. So you could just write something like dotimes 10 beep and your a.s.sistant would write the a.s.sembly language for you (but without bugs).

In fact, this is how most programmers do work. Except the a.s.sistant isn"t a person, but a compiler . A compiler is a program that translates programs written in a convenient form, like the one liner above, into the simple-minded language that the hardware understands.

The more convenient language that you feed to the compiler is called a highlevel language . It lets you build your programs out of powerful commands, like "do something n times" instead of wimpy ones like "add two numbers."

When you get to build your programs out of bigger concepts, you don"t need to use as many of them. Written in our imaginary high-level language, our program is only a fifth as long. And if there were a mistake in it, it would be easy to see.

Another advantage of high-level languages is that they make your programs more portable . Different computers all have slightly different machine languages. You cannot, as a rule, take a machine language program written for one computer and run it on another. If you wrote your programs in machine language, you"d have to rewrite them all to run them on a new computer. If you use a high-level language, all you have to rewrite is the compiler.

Compilers aren"t the only way to implement high-level languages. You could also use an interpreter , which examines your program one piece at a time and executes the corresponding machine language commands, instead of translating the whole thing into machine language and running that.

10.3. Open Source

The high-level language that you feed to the compiler is also known as source code , and the machine language translation it generates is called object code. When you buy commercial software, you usually only get the object code. (Object code is so hard to read that it is effectively encrypted, thus protecting the company"s trade secrets.) But lately there is an alternative approach: open source software, where you get the source code as well, and are free to modify it if you want.

There is a real difference between the two models. Open source gives you a lot more control. When you"re using open source software and you want to understand what it"s doing, you can read the source code and find out. If you want, you can even change the software and recompile it.

One reason you might want to do that is to fix a bug. You can"t fix bugs in Microsoft Windows, for example, because you don"t have the source code. (In theory you could hack the object code, but in practice this is very hard. It"s also probably forbidden by the license agreement.) This can be a real problem. When a new security hole is discovered in Windows, you have to wait for Microsoft to release a fix. And security holes at least get fixed fast. If the bug merely paralyzes your computer occasionally, you may have to wait till the next full release for it to be fixed.

But the advantage of open source isn"t just that you can fix it when you need to. It"s that everyone can. Open source software is like a paper that has been subject to peer review. Lots of smart people have examined the source code of open source operating systems like Linux and FreeBSD and have already found most of the bugs. Whereas Windows is only as reliable as big-company QA can make it.

Open source advocates are sometimes seen as wackos who are against the idea of property in general. A few are. But I"m certainly not against the idea of property, and yet I would be very reluctant to install software I didn"t have the source code for. The average end user may not need the source code of their word processor, but when you really need reliability, there are solid engineering reasons for insisting on open source.

10.4. Language Wars

Most programmers, most of the time, program in high-level languages. Few use a.s.sembly language now. Computer time has become much cheaper, while programmer time is as expensive as ever, so it"s rarely worth the trouble of writing programs in a.s.sembly language. You might do it in a few critical parts of, say, a computer game, where you wanted to micromanage the hardware to squeeze out that last increment of speed.

Fortran, Lisp, Cobol, Basic, C, Pascal, Smalltalk, C++, Java, Perl, and Python are all high-level languages. Those are just some of the better known ones. There are literally hundreds of different high-level languages. And unlike machine languages, which all offer similar instruction sets, these high-level languages give you quite different concepts to build programs out of.

So which one do you use? Ah, well, there is a great deal of disagreement about that. Part of the problem is that if you use a language for long enough, you start to think in it. So any language that"s substantially different feels terribly awkward, even if there"s nothing intrinsically wrong with it. Inexperienced programmers" judgements about the relative merits of programming languages are often skewed by this effect.

Other hackers, perhaps from a desire to seem sophisticated, will tell you that all languages are basically the same. I"ve programmed in all kinds of languages, said the tough old hacker as he eased up to the bar, and it don"t matter which you use. What matters is whether you have the right stuff. Or something along those lines.

This is nonsense, of course. There is a world of difference between, say, Fortran I and the latest version of Perl-or for that matter between early versions of Perl and the latest version of Perl. But the tough old hacker may himself believe what he"s saying. It"s possible to write the same primitive Pascal-like programs in almost every language. If you only ever eat at McDonald"s, it will seem that food is much the same in every country.

Some hackers prefer the language they"re used to, and dislike anything else. Others say that all languages are the same. The truth is somewhere between these two extremes. Languages do differ, but it"s hard to say for certain which are best. The field is still evolving.

10.5. Abstractness Just as high-level languages are more abstract than a.s.sembly language, some high-level languages are more abstract than others. For example, C is quite lowlevel, almost a portable a.s.sembly language, whereas Lisp is very high-level.

If high-level languages are better to program in than a.s.sembly language, then you might expect that the higher-level the language, the better. Ordinarily, yes, but not always. A language can be very abstract, but offer the wrong abstractions. I think this happens in Prolog, for example. It has fabulously powerful abstractions for solving about 2% of problems, and the rest of the time you"re bending over backward to misuse these abstractions to write de facto Pascal programs.

Another reason you might want to use a lower-level language is efficiency. If you need code to be super fast, it"s better to stay close to the machine. Most operating systems are written in C, and it is not a coincidence. As hardware gets faster, there is less pressure to write applications in languages as low-level as C, but everyone still seems to want operating systems to be as fast as possible. (Or maybe they want the prospect of buffer-overflow attacks to keep them on their toes.)

10.6. Seat Belts or Handcuffs?

The biggest debate in language design is probably the one between Those who think that a language should prevent programmers from doing stupid things, and those who think programmers should be allowed to do whatever they want. Java is in the former camp, and Perl in the latter. (Not surprisingly, the DoD is big on Java.) Partisans of permissive languages ridicule the other sort as "B&D" (bondage and discipline) languages, with the rather impudent implication that those who like to program in them are bottoms. I don"t know what the other side call languages like Perl. Perhaps they are not the sort of people to make up amusing names for the opposition.

The debate resolves into several smaller ones, because there are several ways to prevent programmers from doing stupid things. One of the more active questions at the moment is static versus dynamic typing . In a statically-typed language, you have to know the kind of values each variable can have at the time you write the program. With dynamic typing, you can set any variable to any value, whenever you want.

Advocates of static typing argue that it helps to prevent bugs and helps compilers to generate fast code (both true). Advocates of dynamic typing argue that static typing restricts what programs you can write (also true). I prefer dynamic typing. I hate a language that tells me what to do. But some smart people seem to like static typing, so the question must still be an open one.

10.7. OO.