Session 1
A Gentle Introduction to the Study of Programming Languages

Due to the cold temperatures and wind chills, campus was on reduced operations for Tuesday, January 16. Instead of meeting in person, I posted a video to supplement these notes. It is not of the highest quality, as I made it in one take with no editing, but I hope you find it helpful.

Watch this video as you read through these notes. If you click on the link, the video will open in a new tab. You may also download the file to your computer if you'd like by control-clicking on the link.

How Do We Go About Studying Progamming Languages?

This is a course on programming languages. (More on the course title later.) How do we go about studying progamming languages?

Could we just learn a bunch of new programming languages? To learn several new languages well would take a considerable amount of time. Would that teach us much, though? Not necessarily. We would have to select the languages carefully. If we learned Java, then C##, and then C++, we would have seen many of the same ideas in three different forms — and sometimes, not even all that different! What's worse, we would have had to deal with a lot of extra details introduced by each.

Maybe we could study different kinds of languages.

What kinds of programming languages are there? How do we classify languages?

Pause for a moment and write down some of the labels you have heard people use to describe programming languages.

There are a number of different labels we often apply to programming languages, boxes to put them in:

Many of these terms may be new to you. That's okay. But they show us how big the world of programming languages.

What is an example of a declarative language? [SQL]
Functional? [Haskell]
OO? [Java].

What questions can we ask about all these boxes? What questions should we ask?

Yes, there are more:

Wait a minute. Isn't JavaScript is a functional? Isn't Python object-oriented?

This confusion is not accidental. Our categories cut across several different dimensions for labeling languages, including programming style, intended use, complexity, and type of grammar. Even on the issue of style, we encounter confusion. Consider Python or JavaScript. They fit into several different "programming style" boxes! Language designers and users sometimes speak of "multi-paradigm" languages, which are designed specifically so they fit neatly into several different boxes. Is that a new box?

Ack! What are we to do?

Pop Quiz!

Just kidding... Please complete this short survey for me:

I will pause here for five seconds. Please hit your pause button and take five minutes to write down your answers. (You will need them later!) Then re-start the video.

The Tower of Babel
The Tower of Babel (Wikipedia)

How you decide which language is your favorite reveals something about how you think about programming languages right now. We could ask many more questions of this sort:

These aren't trick questions. After at least two semesters in the CS core, you know at least one programming language. You may know two, or be learning a second, from Intermediate Computing. If you use Linux and write shell scripts, you know another. You may have learned a language or two from your job. From noodling on the web, or working on personal projects, you may know some others, or at least know about them. With all this experience, you probably have gut feelings about these issues. I hope that this course gives you more and better tools for understanding and forming your intuitions about programming languages.

Toward a Science of Progamming Languages

Where does this need to classify languages come from? One strong influence: a misguided sense of how to make Computer Science a science.

Scientists draw boxes! They do more, of course, but categorizing is a big part of science. Categories can be how we record our understanding.

Consider these three scientists:

Carl Linnaeus, the creator of biological taxonomy John Dalton, who introduced the atomic theory of matter Erwin Chargaff, who solved the base pair problem with DNA

The first is Carl Linnaeus. He formalized binomial nomenclature, the modern system of naming biological organisms. His taxonomy enabled biologists to categorize living things in a consistent way.

The second is John Dalton, who introduced the atomic theory into chemistry. Look around at the bewildering amount of stuff in the world. Atomic theory outlines the building blocks that make up everything.

The third is Erwin Chargaff, whose experiments solved the base pair problem in DNA (even though he never expressed his results in this way). Chargaff gave us the rules of composition for DNA, creating a grammar of biology.

Scientists create taxonomies, theories of building blocks, and rules of composition in order to express our understanding of the world. Computer scientists have tried to do that for programming languages, too. They have had the best of intentions, but what we see so often is unsatisfying.

The problem: Our boxes are a mishmash of different dimensions. We can't even agree on the atoms. Consider Python. Is it a procedural language? It has classes, so maybe it is object-oriented. Many people consider it a scripting language, because it is so useful for writing small bits of code that glue other components together. It is interpreted, but can be compiled just-in-time. And on and on.

One of the main goals of this course is to help you develop a scientific mindset about programming languages, a way to think about building blocks and rules of composition that leads to taxonomies that computer scientists and professional programmers alike can find helpful.

I won't ban all words used to name the boxes above, even though that might be a great way to run a course. But we will use them in a more limited sense. Programs written in a language can follow a certain style. Subsets of a language can define or support a certain style. But entire languages of the sort we see in industry usually contains big blobs of features that don't fit into only one box.

How would you use a scientific mindset when someone gives you a new programming language? Say, you know Python and the give you Java, or you know Python and maybe Java and they give you, oh, say, Racket.

First, what do they give you when they "give" you a new programming language? They may say that they are teaching you a new way to think or to write program, but that is rather abstract. In addition, they also usually give you two more concrete things:

What do you do then? You look for examples — and run them!

Then you create your own examples. You start thinking, I wonder what happens if...?

This is the moment you start to learn a new language.

One of the challenges we usually face is that they give us big languages. No one wants to learn a toy language. They want to write a game, or a web server, or an operating system. We want more and bigger and powerful.

a big language is usually a blob of features

Even so, in any blob of a language, there is at least one small box that captures its essence: a combination of some building blocks that expresses what you can do and how you can think with a language.

a blob of features can be simplified to a smaller set of corse features

The boxes we drew above are motivated by good intentions and driven by reasonable intuitions, but they are mostly the wrong way to think about programming languages. We want to look for the basic building blocks and the rules for putting them together to make bigger units.

We want to be able to ask a few simple questions of any programming language: Does the language have functions? Are they first-class? Does it have objects? What kind? (Python, Java, JavaScript, and Racket all have objects—different kinds!) Does the language allow mutation? What kind? And so on.

In this course, we will learn about some of the basic building blocks of a program and some of the fundamental rules of composition.

Talking points to close this section:

We seek to desugar a language to its core set of building blocks.
Which ones?
Many different desugarings are available.

examples:
  desugar to Turing machine          (3810: hardware)
  desugar to lambda calculus         (3540: math)
  desugar to a Post rewriting system (3810 or 3610)
  desugar to Game of Life[!]         (written in Racket)

There is no one correct answer.
They are all design choices!
What are the goals of the process?

Course Details

Welcome to CS 3540, Programming Languages and Paradigms. I am Eugene Wallingford, your instructor for the course. It differs from most other CS courses. It is not a theory course, but it does ask you to step outside the confines of any particular programming language: to consider just what a programming language is and how programs written in such a language can be interpreted and executed. I expect that you will find the course challenging, but I also hope that you find it fascinating and rewarding of your effort.

Had we met in person, I would have passed out a short sheet of "vital statistics" that contains basic contact information for me and the course. The most important piece of data on that sheet is all you need: the URL of the course home page:

https://www.cs.uni.edu/~wallingf/teaching/cs3540/

The course web site includes links to:

These materials are organized within a rough schedule for the semester, including tentative dates for three quizzes. Keep this sheet with you at all times. Set a bookmark or open a tab on the web page in your browser. You never know when the urge to study Programming Languages will strike you!

Study the course syllabus carefully. It lists the policies by which we will run this course. You will need to know these policies and when they apply.

Some points to which you should pay special attention:

One thing not on the syllabus that you will learn soon is that you will submit programming assignments online, with only occasional hardcopy.

As I said earlier, this course is likely different from other CS courses you have taken. I think you'll find that it requires a steady effort throughout the semester. But I think that you will find that your effort is adequately reflected in your grade. Warning: You will want to complete all of the assignments — and understand them as well as possible — if you expect to pass the course and earn a desirable grade.

And now for the name of the course...

"Programming Languages ..."

TL;DR:   In this course, we learn only one "real" programming language, as tool for studying the building blocks of progarmming languages. This will help you learn other languages later.

Coming here today, you may not have a very good idea of what this course is all about. You shouldn't feel bad. To this point in your CS education, we have largely confronted you with lots of specifics: how to write programs in a specific language, how to use and implement specific data structures, and how a specific computer executes machine-level instructions. The language has been a tool. Even when we have tried to emphasize issues that are more abstract, your attention has usually been firmly focused on details. This course tries to change that.

Coming here today, you may think of a programming language as nothing more than "something you use to write computer programs". That is true, but circular. It doesn't shed much light on why Python and Java exist, or why they are the way the are. Thinking about languages in terms of the programs we can write is pretty handy in a world that enables us to earn a living writing programs. But that view limits our thinking — and sometimes limits the living we can earn by writing programs.

One definition of "programming language" I find useful is from Abelson and Sussman :

A programming language is a framework for organizing ideas about processes.

When you study computer science, you are learning more than vocational skills. CS is also a discipline that explores a set of big ideas that swirl around representation, computation, and process. It gives us tools for talking about ideas we had a hard time even expressing before.

We write computer programs for a lot of reasons: to solve a problem, to understand some part of the world better, to make money. Whatever the reason, we eventually want to be able to execute the program and see a result.

Other disciplines also build models to help them understand the world. What makes CS different is that we can run our models: they are alive when executed on a computer!

In this course, we will study a few important concepts of programming languages by reading and writing language processors that expose individual concepts.

"... and Paradigms" — Um, What?

TL;DR:   A programming paradigm is what I called a "style" earlier. The procedural programming you learn in the intro course is a style. Functional programming is a style. Object-oriented programming is a style. They are not incompatible with one another. You can learn and use all of them (and more).

What about the second part of the course name, paradigm? This word has been a buzzword in business and science for many years. A simple dictionary definition of the word is:

paradigm
1 : EXAMPLE, PATTERN, especially an outstandingly clear or typical example
2 : [...]
3 : a philosophical and theoretical framework of a scientific school or discipline within which theories, laws, and generalizations, and the experiments performed in support of them, are formulated

The first definition refers to a model or pattern for something that may be copied. The second refers to a theory or a group of ideas about how something should be done or thought about.

The third definition is the one most people mean these days when they use the word, especially in business and science. In this sense, a programming paradigm is a theoretical framework within which we think about and write programs. Different theories provide different ways of thinking about computations and thus give rise to programs of different form.

This is the usage of 'paradigm' that became popular in the worlds of business and science several decades ago, and it filtered into computer science.

Actually, though, the first definition is a better way for us to think about different kinds of programming. A paradigm is a pattern or example of how to program.

We will understand this idea more as the semester goes on and we talk about styles of programming. For now, though, we can think about paradigms in a more familiar context: human languages. If you are a fluent English speaker, which is easier to learn: German or Mandarin? Probably German, because it is more similar to English than Mandarin. German comes from the same framework, the same "family" of languages, as English.

The same is true of programming languages. If you are a fluent programmer of Python, then it may be easier to learn C than, say, Smalltalk. This is not because Smalltalk is harder to learn in its own right, but because it is a different kind of language. But a Java programmer may find learning Smalltalk a bit easier, despite the fact that Java and C look very much alike — much more so than Python resembles C — because Java and Smalltalk are alike in some very important ways. They are members of the same language family.

Programming languages resemble human languages in another respect, too. The environment and history of a group of people help to create its culture, and the language that a group of people uses both shapes the culture and comes to reflect the culture, and thus its environment and history. Much of what we mean when we say "programming paradigm" is a reflection of programming culture.

A Second Goal for the Course: Another Style

TL;DR:   This semester, you will learn to program in a functional style using the Racket programming language. It may seem strange at first, because it is different from what you are used to. But it offers advantages that make it worth the effort.

You have all written programs that include and use functions. Here is a simple example in Python:

def square(x):
    return x * x

Of course, we also write code that looks like this:

def processNext():
    message = InboxQueue.popMessage()
    if message:
        process(message)

processNext doesn't return a value, so it's not really a function at all. We might call it a "procedure".

But there's more. It looks like processNext takes zero arguments, but notice that it refers to a value from outside the code: InboxQueue. That means processNext depends on the state of the world outside the code. InboxQueue is a hidden input to the function. Even more, processNext seems to change the state of the world outside the code when it pops a message from InboxQueue.

Functional programming is a style of programming in which functions receive data as input, process only that data, and return a value. The word "only" is the key.

In functional programming, programmers abstain from two habits common in other styles:

Without state and mutation, the behavior of each function is self-contained: we don't need to look anywhere else to determine what it does and how it works. As a result, it is easier to prove things about the function's behavior. Computer scientists often want to do that. It is also easier to reason about the function and to test it, which programmers need to do as a part of their jobs. In this course, want to write programs that analyze other programs, and using a functional style for the inputs makes them easier to process.

Programming with functions isn't really new to you, but programming in a functional style requires a new kind of dicipline. It may feel uncomfortable for a while, but you'll be surprised how easy the style feels to you after a few weeks of practice.

Morpheus, that cool dude from The Matrix
I'm trying to free your mind, Neo. — Morpheus

This semester, you will program in Racket, a language that makes functional style a more obvious choice. It may seem strange at first, too, because it is different than what you are used to. But it, too, will become familiar over time. And you will find that it is a language perfectly suited to developing a scientific mindset about program languages.

One of the goals of the course is to help you become familiar with the functional style of programming, to broaden your idea of what a programming language can be, and to broaden your idea of what programming itself can be.

Make a good faith effort to learn Racket, and you will be rewarded many-fold. Just imagine what the world would have been like if folks had shied away from learning to fly airplanes because they were so different from driving trains and automobiles? What trade-off did we make between complexity and power?

My Answers to the Pop Quiz

It is only fair that I come clean, too. This section is optional. Read it if you'd like to know a little more where I am comin om.


My favorite languages give me the power to express interesting ideas with some ease, with some flexibility, and with some elegance. I like some languages primarily because they give me a particular kind of power in a particular kind of domain (say, Cobol for data processing and report generation). And I like some languages just because they are beautiful!

Why do we have all these different languages? Because some problems demand certain features, which can often be optimized in a special-purpose language. Because researchers and practitioners are always looking for better ways to express interesting ideas and solve challenging problems. Because we have lots of different kinds of programmers.

What makes one language "better" than another? The combination of its feature set plus the environment in which it will be used. (Note that this is different from what makes one language more popular, a question with a different answer!)

What makes one language easier to learn? Primarily, familiarity — with the paradigm, with the syntax. After that, simplicity. And don't underestimate the closeness of the match between the language's primitives and the language of the problem.

Can a program be beautiful? How about a programming language? How so? Oh, my — yes, and yes! A program like Adobe Photoshop is beautiful in how it weds simplicity, power, and usability. Ward Cunningham's original wiki software is beautiful in its simplicity, power, and ability to change how people interact. The decorator design pattern is beautiful in its ability to tease apart orthogonal ideas and make the code I write say just what I mean.

A programming language like Scheme is beautiful in the way it allows programmers to use a small number of simple ideas to express a vast number of complex ideas elegantly. Smalltalk is beautiful in the same way, as it starts with exactly one idea: "objects send messages to one another", and from it builds an environment of unbelievable creativity and flexibility.

Don't get me started. But I hope that, even if you don't understand what I'm saying about beauty today, by the end of the semester you sense my love for the beauty of programming languages.

Wrap Up