In the beginning, there was assembly language.
For now, here are my talking points for the story. They are a little rough, so I'll leave them in plaintext.
What a tough teacher I am... A quiz on the first day. Don't worry; everyone will ace it.
How you decide which language is your favorite reveals something about how you think about programming languages. 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.
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.
I 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 URL of the course web page:
The web site there includes pointers to a full syllabus, all the materials you'll need for the course (including lecture notes, homework assignments, and exams), and links to programming material and other resources for the course. Keep this sheet with you at all times, and set a bookmark to the web page in your cloud service. You never know when the urge to study Programming Languages will strike you!
Study the course syllabus carefully, especially if you've never had me for a course, but even if you have. It lists the policies by which we will run this course. You will need to know these policies and when they apply. You will also find a rough schedule for the semester on the last page, including very tentative dates for four exams.
Some points to which you should pay special attention include:
One thing not on the syllabus that you will learn soon is that you will submit programming assignments both online and in hardcopy. Please follow the instructions!
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.
Welcome to CS 3540, Programming Languages and Paradigms. This course is a pivotal point in your computer science education. It steps back from specific programming languages and considers what it means for something to be a language, and what it means for programmers to use one.
This is an exciting course because, in it, you have a chance to look behind the curtain of tools you use everyday. Until this course, you have probably treated compilers and interpreters for programming languages as if they were magic: you understood what your program did (well, maybe...), but you weren't sure how the Python interpreter or the Java compiler made it work.
Everywhere we look in computing, we see languages: programming languages, yes, but also many other kinds of languages and protocols. Languages shape what we compute, and how. After you complete this course, you will understand a little bit about how language processors do their thing -- and more about the programming languages you use. This will make you better at writing programs, learning new languages, and even using and configuring programs.
To be honest, I intend for this class to be subversive. If I succeed, you will leave the course questioning the authorities. But the authorities I'd like to knock down are not political or religious authorities. They are technological ones, including Python, Java, and C.
The creation story I told above traced the evolution of one programming language idea, as an example of how programming languages developed and evolved more generally. That story also lays the groundwork for what we do and study in this course...
For now, here are my talking points for the rest of the story.
What about the name of the course?
TL;DR: In this course, we learn only one "real" programming language, as tool for studying the ideas that make up a language. 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.
My favorite definition of "programming language" 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.
This semester, we will build interpreters, a particular sort of language processor. An interpreter takes a program as input and produces the result of the program:
Some interpreters you might know include:
(An algebra student? Consider the movie Hidden Figures. In it, the "computers" were people!)
Another kind of language processor is a compiler, which takes a program as input and produces another program as its output:
We then feed that program to another processor, and ultimately to an interpreter than can produce a result. A Java compiler produces Java bytecode, and we give the bytecode to the JVM (an interpreter) to produce a result. An Ada compiler usually produces machine language, say, x86 machine language, which we execute directly on a machine.
In this terminology, a person who translates Chinese to English is a compiler, not an interpreter. A person who listens to Chinese and acts according to what she hears is an interpreter.
These two pictures tell only part of the story. Whether we interpret or compile a program, we almost never operate on the program text itself. The language process first converts the text of the program into some internal representation of the program, which it then processes further:
This semester, we use interpreters to help us learn about programming languages. We consider what sorts of features we can represent in a program and how we can determine the behavior of a program. In CS 4550, you can learn more about parsing and compiling, and even build a compiler yourself!
I hope that you are beginning to see why I say that CS 3540 is a pivotal point in your CS education. It is the lynchpin of all that we do as computer scientists. Without a firm understanding of how programming languages work, you cannot grow much more as a computer scientist. This course can help you understand how individual languages work, but also what kinds of languages there are (and can be), what is involved in designing and interpreting a language, how paradigms evolve, and so on.
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:
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 second 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 a couple of 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 Chinese? Probably German, because it is more similar to English than Chinese. German comes from the same framework, the same "family" of languages, as English.
The same is true of artificial languages like programming languages. If you are a fluent programmer of Python, then it is probably 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. Environment and history help to create a 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.
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 an example in Python:
def square(int x): return x * x
We often 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; it's a procedure. But there's more. It looks like processNext that takes zero arguments, but it refers to a value from outside the code: InboxQueue. What processNext does depends on the state of the world outside the code. InboxQueue is a hidden input to the function. Even more, processNext changes the value of InboxQueue by popping a message.
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 to determine what it does and how it works. As a result, it is easier to prove things about the functions'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.
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.
In reality, both functional programming and Racket are quite simple -- perhaps too simple. 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?
It is only fair that I come clean, too.
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 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.
Everywhere we look in computing, we see languages: programming languages, yes, but also
Return to the reading.
Homework 0 is available and due at the beginning of our next class, 12:30 PM on January 16. As the assignment says, bring hardcopy of your write-up to class next time. There is no electronic submission for this one.
Begin to learn about the tools you will use to program in Racket this semester. Time permitting, download Dr. Racket and begin to explore!