Notes on "Growing a Language"
Revisiting one of my favorite talks ever, on designing programming languages for user extensibility and collaboration
If you care enough about programming languages (and every framework, every library has aspects of a language), you come to care intensely about programming language design. This is one of the few accessible, entertaining talks that tackles this head on.
I'm watching it again in preparation for an upcoming talk so here are my public notes.
- You should design languages to start small and then grow.
- You should design languages so that users help you grow them easily.
- The solution to the Cathedral vs Bazaar is let everyone play but have a BDFL decide what to take in/out. Have a Shopping Mall of good ideas.
- It is good for you and your users, to give them a chance to buy in and pitch in.
- If you design a small number of useful patterns, you can say no to a lot more things that not everybody uses, while letting them define things they will use.
- Generic Types and Operator Overloading are 2 such patterns that let users solve all sorts of problems.
- Going meta: We should now think of a language design as a pattern for language designs, a tool for making more tools of the same kind.
- Use simple words in real life too.
⚠️ Note - a lot of these are lifted verbatim from the transcript as I am just doing a first pass of notes right now.
A language that is too small is hard to use. You can't say much at all until you take the time to define at least a few new terms.
If you want to get far at all with a small language, you must first add to the small language to make a language that is more large.
I need to design a language that can grow. I need to plan ways in which it might grow—but I need, too, to leave some choices so that other persons can make those choices at a later time.
We have known for some time that huge programs can not be coded from scratch all at once. There has to be a plan for growth. What we must think on now is the fact that languages have now reached that large size where they can not be designed all at once, much less built all at once.
At times we think of C as a small language designed from whole cloth. But it grew out of a smaller language called B, and has since grown to be a larger language called C plus plus. A language as large as C plus plus could not have spread so wide if it had been foisted on the world all at once.
Worse is Better: The gist of it is that the best way to get a language used by many persons is not to design and build 'The Right Thing,' because that will take too long. In a race, a small language with warts will beat a well designed language because users will not wait for the right thing; they will use the language that is quick and cheap, and put up with the warts. Once a small language fills a niche, it is hard to take its place.
Languages must do a lot more things than they used to:
They need to paint bits, lines, and boxes on the screen in hues bright and wild; they need to talk to printers and servers through the net; they need to load code on the fly; they need their programs to work with other code they don’t trust; they need to run code in many threads and on many machines; they need to deal with text and sayings in all the world’s languages. A small programming language just won’t cut it.
So a small language can not do the job right and a large language takes too long to get off the ground. Are we doomed to use small languages with many warts because that is the sole kind of design that can make it in the world?
No. Start small, then grow.
If one person does all the work, then growth will be slow. But if one lets the users help do the work, growth can be quick. If many persons work side by side, and the best work is added with care and good taste, a great deal can be added in a short time.
Let the user define new words in a way that they look like primitives. In this way the user can build a larger language to meet his needs. (Hooks pass this test).
In APL, new words don't look like primitives. To add to APL, it takes a lot of work - this has stopped users from helping to grow the language. To adopt userland code into the language takes a total rewrite.
In Lisp, new words defined by the user look like primitives and, what is more, all primitives look like words defined by the user. In other words, if a user has good taste in defining new words, what comes out is a larger language that has no seams. The designer in charge can grow the language with close to no work on his part, just by choosing with care from the work of many users.
So Lisp grew much faster than APL did, because many users could try things out and put their best code out there for other users to use and to add to the language.
A main goal in designing a language should be to plan for growth. The language must start small, and the language must grow as the set of users grows.
I, as a language designer helping out with the Java programming language, need to ask not 'Should the Java programming language grow?' but 'How should the Java programming language grow?'
if the goal is to be quick and yet to do good work, one mode may be better by far than all other modes.
There are two kinds of growth in a language. One can change the vocabulary, or one can change the rules that say what a string of words means.
A library is a vocabulary designed to be added to a programming language to make its vocabulary larger. A true library does not change the rules of meaning for the language; it just adds new words. The key point is that the new words defined by a library should look just like the primitives of the language.
It may be good as well to have a way to add to the rules of meaning for a language.
Cathedral vs Bazaar
- There are 2 ways to do the growing - One person-or a small group-to be in charge and to take in, test, judge, and add the work done by other persons. The other way is to just put all the source code out there, once things start to work, and let each person do as he wills. To have a person in charge can slow things down, but to have no one in charge makes it harder to add up the work of many persons.
- The way that I think is faster and better than all others does both. Put the source code out there and let all persons play with it. Have a person in charge who is a quick judge of good work and who will take it in and shove it back out fast. You don’t have to use what he ships, and you don’t have to give back your work, but he gives all persons a fast way to spread new code to those who want it.
- As for the role of programmer in charge, Eric Raymond says that it is fine to come up with good thoughts, but much better to know them when you see them in the works of other persons.
- The key point is that in the bazaar style of building a program or designing a language or what you will, the plan can change in real time to meet the needs of those who are working on it.
- This tends to make users stay with it as time goes by; they will take joy in working hard and helping out if they know that their wants and needs have some weight and their hard work can change the plan for the better.
HIGH POINT OF THE TALK: The Importance of Patterns
- Christopher Alexander says: Master plans have two additional unhealthy characteristics. To begin with, the existence of a master plan alienates the users. After all, the very existence of a master plan means, by definition, that the members of the community can have little impact on the future shape of their community, because most of the important decisions have already been made. In a sense, under a master plan people are living with a frozen future, able to affect only relatively trivial details. When people lose the sense of responsibility for the environment they live in, and realize that they are merely cogs in someone else’s machine, how can they feel any sense of identification with the community, or any sense of purpose there?
- Does this mean, then, that it is of no use to design? Not at all. But in stead of designing a thing, you need to design a way of doing.
- A pattern is a plan that has some number of parts and shows you how each part turns a face to the other parts, how each joins with the others or stands off, how each part does what it does and how the other parts aid it or drag it down, and how all the parts may be grasped as a whole and made to serve as one thing, for some higher goal or as part of a larger pattern. A pattern should give hints or clues as to when and where it is best put to use. What is more, some of the parts of a pattern may be holes, or slots, in which other things may be placed later.
- A generic type is a map from one or more types to types. Put another way, a generic type is a pattern for building types.
- A word is said to be overloaded if it is made to mean two or more things and the hearer has to choose the meaning based on the rest of what is said. For example, using the rules defined near the start of this talk, a verb form such as 'painted' might be a past tense or a past participle, and it is up to you, the hearer, to make the call as to which I mean when I say it. Just as a user can code methods in just the same way as methods that are built in, the user ought to have a way to define operators for user defined classes that can be used in just the same way as operators that are built in.
- If we grow the language in these few ways, then I think we will not need to grow it in a hundred other ways; the users can take on the rest of the task. (Examples with number types - cannot add all of them at once even tho each individually may have a good usecase)
- Some parts of the programming vocabulary are fit for all programmers to use, but other parts are just for their own niches. It would not be fair to weigh down all programmers with the need to have or to learn all the words for every niche used.
- We should not make the Java programming language a cathedral, but a plain bazaar might be too loose. What we need is more like a shopping mall, where there are not quite as many choices but most of the goods are well designed and sellers stand up and back what they sell.
- When a language gives you the right tools, such classes can be coded by a few and then put up as libraries for other users to use, or not, as they choose; but they don’t have to be built in as part of the base language. If you give a person a fish, he can eat for a day. If you teach a person to fish, he can eat his whole life long. If you give a person tools, he can make a fishing pole—and lots of other tools! In this way he can help other persons to catch fish.
- Meta means that you step back from your own place. What you used to do is now what you see. What you were is now what you act on. Verbs turn to nouns. What you used to think of as a pattern is now treated as a thing to put in the slot of an other pattern.
- We should now think of a language design as a pattern for language designs, a tool for making more tools of the same kind. A language design can no longer be a thing. It must be a pattern—a pattern for growth—a pattern for growing the pattern for defining the patterns that programmers can use for their real work and their main goal.
- In the course of giving this talk, because I started with a small language, I have had to define fifty or more new words or phrases and sixteen names of persons or things; and I laid out six rules for making new words from old ones.
- It should give no one pause to note that the writing of a program a million lines of code in length might need many, many hundreds of new words—that is to say, a new language built up on the base language.
- Language design is not at all the same kind of work it was thirty years ago, or twenty years ago. Back then, you could set out to design a whole language and then build it by your own self, or with a small team, because it was small and because what you would then do with it was small. Now programs are big messes with many needs. A small language won’t do the job.
- It would be great if there were some small programming language that felt large, the way Basic English is small but feels large in some ways. But I don’t know how to do it and I have good cause to doubt that it can be done at all.
- So I think the sole way to win is to plan for growth.
- Parts of the language must be designed to help the task of growth- of growing the language.
Plan for Warts
- You may find that you need to add warts as part of the design, so that you can get it out the door fast, with the goal of taking out the warts at a later time.
- With care, one can design a wart so that it will not be too hard to take out or patch up later on.
- Some warts are not bad things you put in, but good things you leave out. Have a plan to add those good things at a later time, if you should choose to do so, and make sure that other parts of your design don’t cut you off from adding those good things when the time is right.
- If we add hundreds of new things to the Java brand programming language, we will have a huge language, but it will take a long time to get there. But if we add a few things— just the right things- generic types, operator overloading, user defined types of light weight, for use as numbers and small vectors and such— and some other things- that are designed to let users make and add things for their own use, I think we can go a long way, and much faster. We need to put tools for language growth in the hands of the users.
- I hope that we can, in this way or some other way, design a programming language where we don’t seem to spend most of our time talking and writing in words of just one syllable.
- (In designing this talk) there was this choice for each new word: is it worth the work to define it, or should I just stick with the words I have?
- I learned in my youth, from the books of such great teachers of writing as Strunk and White, that it is better to choose short words when I can. I should not choose long, hard words just to make other persons think that I know a lot. I should try to make my thoughts clear; if they are clear and right, then other persons can judge my work as it ought to be judged.
- Short words work well, if we choose them well.
- All in all, I think it might be a good thing if those who rule our lives—those in high places who do the work of state, those who judge what we do, and most of all those who make the laws—were made to define their terms and to say all else that they say in words of one syllable. For I have found that this mode of speech makes it hard to hedge. It takes work, and great care, and some skill, to find just the right way to say what you want to say, but in the end you seem to have no choice but to talk straight. If you do not veer wide of the truth, you are forced to hit it dead on.