Summary
- What is a programming language
- Trade-offs: more convenient for the human or for the machine? Faster to write or faster to execute?
- Expressivity and precision
- Interpreters and Compilers
- Course policy
Language
Humans use language to communicate ideas with each other. Arguably our use of language is a big distinction in what it means to be human, and a huge advantage our ancestors had in developing and passing along knowledge — to us!
Many of you will know or at least have some familiarity with languages other than English. Think for a moment about what these languages have in common, and how they differ.
Two important aspects (which of course also apply to programming languages) are expressivity and precision. Expressivity is about being able to describe something easily or naturally, and precision is about making it clear exactly what you mean.
For example, German has a single word Kummerspeck which means, roughly, the weight one gains from overeating during stressful times. Describing this same concept in English is possible, but it’s a bit more awkward and lengthy; we might say German is more expressive on this topic.
For another example, consider the sentence “I saw her duck.” Is this referring to someone’s quacky pet, or to bending down? That’s an example of how English (and probably every human language) can be imprecise, leading to multiple different interpretations of the same words.
Programming Languages
A programming language has a similar goal of human languages: it’s a set of rules and practices for communicating, or expressing ideas, between two different individuals. Except of course, that one of those individuals is (usually) a computer!
In terms of precision, we have much higher standards for programming langages than human ones. Generally speaking (we will talk about it more next class!) in a well-designed programming language, there should only be exactly one meaning of any given program. Ambiguity is sometimes helpful in human speech, and perhaps necessary for us to express complex emotions and so on, but in programming languages it’s to be avoided!
In terms of expressivity, programming languages are much more limited than human languages. We don’t need to talk about stress eating or feathered friends in a programming language; we just need to explain what we want the computer to do.
Still, expressivity can differ greatly between programming languages. For example, here is a C program to get the first 50 Fibonacci numbers in an array and then print them out:
#include <stdio.h>
#include <stdlib.h>
int main() {
long *fibs = malloc(50 * sizeof(long));
fibs[0] = 0;
fibs[1] = 1;
for (int i = 2; i < 50; ++i) {
fibs[i] = fibs[i-2] + fibs[i-1];
}
for (int i = 0; i < 49; ++i) {
printf("%ld ", fibs[i]);
}
printf("%ld\n", fibs[49]);
free(fibs);
return 0;
}
In Haskell, due to something called lazy evaluation which we might learn about later in the semester, we can do exactly the same computation like this:
fibs = 0 : 1 : (zipWith (+) fibs $ tail fibs)
take 50 fibs
Roughly, these two lines translate to:
fibsis a list of numbers. The first two numbers are 0 and 1. For the rest of the numbers, take the entire list starting from 0, and the same list starting from 1, and add up each pair of numbers from those two infinite lists.- Show me the first 50 numbers from this infinite list.
And yes, it actually works! (Try it with ghci in a terminal if you
dare.)
The point is, Haskell is much more expressive here because it allows us to work with things like “imagined” infinite lists on a real computer, which isn’t really possible in C.
Tradeoffs
Programming languages are inherently a compromise. They are meant for communication between humans and computers, so we shouldn’t expect them to be perfect for either the human or the computer.
We just saw an example of Haskell and C, where the Haskell language ends up being much more expressive. But that doesn’t mean Haskell is a “better” language than C, just that it has different trade-offs and capabilities. Compared to Haskell, C is much closer to how the computer actually works for example, allowing for much faster execution at run-time.
Compiled vs Interpreted
Remember the title of this course: Programming Languages and Implementation. What is that last part about? It means somehow getting that program written in some programming language to actually run on a real computer.
There are generally two ways that this happens:
-
An interpreter is a computer program which reads in source code, and directly executes it. When you run
python3on the command line for example, you get a live interpreter of any Python commands you type in. -
A compiler is a computer program that translates from one programming language into another one. Usually we want to eventually translate into the native language of the CPU, which is machine code.
These two approaches actually share a lot in common, as we will see. They both need to read source code and understand what the programmer is saying. But the compiler must then go a step further and output code in another lower-level language.
Interpreters are generally a bit easier to create, and allow for more flexible code. But compilers are actually still involved no matter what; the interpreter itself probably needed to be written in a compiled language at some point!
Goals of the class
The course policy states the class learning objectives in kind of a formal way.
To put it more succinctly, we are trying to accomplish a single thing:
You are going to design a new programming language, and an interpreter and compiler for that language, from scratch.
That’s really it! But it’s going to be a long, tough journey to get there.
There are many reasons why we are doing this:
-
By carefully specifying how your language is supposed to work, you will gain an appreciation for and develop skill at understanding technical specifications in general.
(This is useful not just for picking up new programming language, but really for reading or creating any technical documents.)
-
By implementing your language in an interpreter and compiler, you will gain a tremendous understanding of how the code you write in any language is executed.
In short, you will become a more savvy programmer.
-
By doing this yourself, and going through the hard (collaborative) work of figuring it out, you will have lots of chances to make mistakes, learn from them, and correct your work — all of which take time but are also the best way to learn and develop critical thinking skills.
-
Designing and building things yourselves is much more fun than being told what to do all the time! And you are ready for it.