Programs are living expressions of thought, and programming languages are the medium of
those expressions. A good language delivers power into the hands of
programmers. It makes it possible for them to write expressive
programs—clear, concise, elegant and efficient.
In this course we will study programming languages, and how they enable this
kind of expressiveness. We will look at the basic concepts of languages, and
how different kinds of language mechanisms can fit together in different ways.
The material will be intellectually substantive and challenging. At the same
time, it should be practically useful over your career.
You will learn to see the similarities and differences among the thousands of
languages we use every day. You will learn not to be fazed as new languages
come and go. You will also learn how to design and/or choose a new language when that might make a program you want to develop much easier
The course involves programming, thinking, and good fun discovering what
languages, programs and computations really are.
Welcome to 311. I hope you find the course rewarding.
High-level course learning goals
In large part, a programming language is defined by a set of individual
language design choices. We will explore the space of languages
by exploring the axes that define these choices.
What language design choices and features will we study? Likely examples:
types: records, polymorphism, subtyping, type checking and type inference
All of these are really about semantics: how do we describe what
a language feature means?
There are many kinds of meaning. A program can be understood both as
a text (source code) and as an actor that does something.
The semantics of a language must be grasped from both ends:
static semantics: What can we learn about a program by thinking of it
as a dense, highly structured text? What can we know about
its behaviour (what it does) without actually running it on a computer
or in our heads?
How should we define what programs in a language do,
so that a language implementor will know what to build,
and so that a programmer can run programs in their head?
Given all that, our parameterizable high-level learning goals are for you to be able to:
Assess the semantics of a (new or existing) language as a collection of language design decisions and describe the likely impact of some of those decisions on the language and its programmers.
Indicate through examples how different design choices for programming language features alter the semantics of syntactically identical code (e.g., giving a code snippet that behaves differently under static and dynamic notions of typing, and explaining why).
Justify or criticize a particular design decision for a programming language
feature in the context of a design goal for the language as a whole.
For example, (1) Criticize dynamic scope. (2) Criticize static type inference. (You should be able
to criticize a design choice even if you agree with it!)
Read, write, and modify syntax specifications, abstract syntax
specifications/datatypes, parsers, stepping rules, interpreters, typing rules,
and (as appropriate) type checkers for various languages illustrating key programming
Read, write, and modify Racket (and Racket-like) programs as test cases
and illustrative examples for the various languages we develop and study (and for the
corresponding functionality in Racket itself). (These will be short, since short
programs generally suffice for tests/examples.)