Letters to a Computer
Programming a computer is like writing a letter to a friend. Our letters to humans introduce new babies, injuries, and recipes, just as our letters to computers introduce new data, changed variables, and functions. We write to our human correspondents asking them to perform tasks for us: water the plants, send us a copy of that photo. Likewise, we ask our computer correspondents to perform tasks: sort this list of numbers, find the fastest route. Our letters to computers—programs—tend to be direct and commanding, containing none of the pleasantries we expect in communication between humans. Nevertheless, upon receiving a letter, the computer dutifully gets to work on our behalf and performs the computation we request.
Writing letters and writing programs are both iterative processes. You don't sit down knowing exactly what to say, but each draft helps you form your thoughts and gets you closer to communicating them clearly.
We write and program in order to move thoughts from one being to another. When beings are physically separate from one another, they need a bridge to span the gulf between their thinking machinery. Language is that bridge. It is an association between internal thoughts and external symbols. When I want you to think a certain thought, I encode it using the associated symbols. I hope that you receive the symbols intact and that you decode them using the same associations that I used to encode them.
Letters between humans are written in human languages like English, Spanish, and Japanese, while letters to computers are written in programming languages like Ruby, Haskell, and Rust. As with humans, there's a gulf between the programmer and the computer. In order for a programmer and computer to work together, they need a shared agreement that associates symbols and actions that the computer is to take. A programming language is that agreement between human and machine.
What then makes a language a programming language? Perhaps the difference is that the intended audience of a program is a computer. Abelson and Sussman claim that programming is very much a human activity in Structure and Interpretation of Computer Programs:
Programs must be written for people to read, and only incidentally for machines to execute.
An alternative definition of programming language might be a language through which programmers describe an algorithm. But this too may be overly narrow. When you write a database query, you aren't describing an algorithm. Are you programming? Is the query language a programming language? When you mark up a document with HTML tags, are you programming?
Maybe you can think of a better definition.
At this point in your study of computer science, you probably know a few programming languages. In this course, you will learn a few more. But our objective is deeper. This course is about the wide variety of ideas that humans have had about how to program computers over the past several decades. Our goal is to help you see the expansive design space of programming languages. We will look at this design space primarily through the lenses of Ruby, Haskell, and Rust. But we will also encounter C, C++, Java, JavaScript, Kotlin, and a few other languages with interesting features.
In this chapter, we postpone our discussion of any particular programming language and instead examine programming languages as a subdiscipline of computer science. By the end of this chapter, you'll have first-draft answers to these questions:
- Why is there a programming languages course in most university computer science programs?
- Why are there so many programming languages?
- How does a program written in a high-level language get executed by a CPU that only responds to a small set of low-level instructions?
- What notation and tools do language designers use to invent new languages?
This book is just another letter between humans. May its tangible symbols trigger some intangible thoughts about programming languages in your brain.