Computer Science 541
studies modern programming languages, with an emphasis on design and semantics.
This document specifies the course's general and specific objectives.

The study of programming languages is primarily concerned with the
following questions:

What are good ways to program?
That is, what are expressive ways of specifying computational processes?

How can a (good) strategy for programming be effectively expressed?

What are the costs of various ways of programming and expressing programs?
And how can those costs be lowered?

Com S 541 addresses all these questions to some extent.
In addressing the third question, however, we focus on the costs of programming
in terms of human time and effort,
not on machine efficiency (time and space costs) or on issues of compilation.

The catalog description of the course is as follows:

Survey of the goals and problems of language design.
Formal and informal studies of a wide array of programming
language features including type systems, naming, state,
and control. Creative use of functional, object-oriented,
declarative, concurrent and other programming paradigms.
(3 credits).

Com S 541 is distinguished from
Com S 342 (Principles of Programming Languages)
is that Com S 342 concentrates on essential semantic concepts,
studied with the use of interpreters (coded in a functional style).
Com S 342 avoids mathematical formalisms, while in Com S 541,
we will not shy away from them.
In this version of Com S 541, we concentrate on mathematical semantics.
In Com S 541 we aim to study modern
functional
and
object-oriented
languages,
and assume that the graduate students are capable of dealing with
the realistic versions of such languages.
In Com S 541, we try to use mathematical tools to draw design lessons from
our study of semantics, as opposed to simply understanding the features of
modern languages.

Com S 541 is distinguished from
Com S 641 (Semantics of Programming Languages)
in that Com S 641 discusses particular formal semantic description techniques
in depth, whereas a broader and less mathematically deep use
of semantic description techniques is made in Com S 541;
furthermore, an attempt is made in Com S 541
to show how to use these techniques in language design.

The course described here was developed with the help
of Kelvin Nilsen.
Final exams for similar courses at other universities were provided by
Uday Redy (University of Illinois), John Mitchell (Stanford),
Dan Friedman and J. Michael Ashley (Indiana),
and Dave Gifford and Franklyn Turbak (MIT);
these helped provide perspective on what is important for such a course.
My early ideas for this course were formed as a teaching assistant
in similar graduate courses led by Dave Gifford and John Guttag of MIT.
Other ideas have been shaped by Barbara Liskov, Lawrence Flon,
Per Brinch-Hansen, and students in previous editions of CS 541.

Com S 541, ``Principles of Programming Languages,''
is usually taken by first year graduate students (if they have sufficient
background).
The class has a ``lecture'' that meets 3 times a week, for 50 minutes a time.
It also has a discussion section that meets once a week (for 50 minutes)
with a teaching assistant.
There are usually 44 or 45 lecture meetings in a semester.
The course carries 3 credit hours.

The formal prerequisite in the Iowa State catalog
is successful completion of Com S 442 (Principles of Compiling);
that is, successful completion of an undergraduate course
in compiler construction.

The skills taught in Com S 442 relevant to Com S 541 include the ability to:

read and write context free grammars,

estimate the run-time costs of various language features,
such as parameter passing mechanisms,

modularize, document, and manage a large and evolving piece of software.

At Iowa State
Com S 342 (Principles of Programming Languages)
is a prerequisite for Com S 442,
which means that you should already have some understanding of
``language design concepts,'' ``run-time implementation'' techniques,
and ``major features of various programming languages.''
These topics are perhaps more directly relevant to Com S 541 than the material
in Com S 442, but at many schools some of these topics are covered in a
course on compiler construction.
The skills of Com S 342 relevant to Com S 541 include the ability to:

Modify interpreters to change or enhance their behavior so as to
implement various features of programming languages such as: control
flow, variables, recursion, scoping, syntactic sugars,
arrays, parameter passing mechanisms, objects, and inheritance.

Write programs using such features,
and explain (using appropriate terminology) and answer questions about
the user-visible behavior of such programs.

Explain (using appropriate terminology) and answer questions about
the data structures and algorithms used in interpreters to
implement such features.

Compare alternatives in the design and implementation of such features.

If you do not have this background,
especially if you are interested in research in programming languages,
you should take Com S 342 or Com S 442 (preferably both if you want to do
research in this area).
Mere reading of texts on these subjects is not enough.

The general objectives for Com S 541 are divided into two parts:
a set of essential of objectives and a set of enrichment objectives.
The essential objectives will be helpful for your career
as a computer scientist, regardless of your particular speciality;
hence you are required to master them to some extent.
You are not required to master the enrichment objectives,
although you are encouraged to explore them both for their own sake
and because learning more about those will help deepen your understanding
of the essential objectives.

Essential Objectives

In general terms the essential objectives for Com S 541 are
that you be able to:

Solve problems using the functional, object-oriented,
and declarative paradigms.

Understand the major features of modern programming languages and
their semantics.

You will be expected to complete all the tasks above without references,
except writing programs and formally specifying languages.

Language design is fundamental to mathematics and science
because a crucial step in solving a problem
is designing an adequate notation for stating the problem
(the specification) and expressing the solution.
In computer science, unlike mathematics and the traditional sciences,
because computers are general purpose tools,
we tend to look at widely different problems.
Problems from different application domains often come without
a familiar or ready-made notation;
thus the computer scientist often finds it convenient to
develop a special-purpose notation.
In developing such a special-purpose notation
(e.g., a specification language or programming language)
it is helpful to draw on the results
of programming language research.
These results will help you in generating plausible designs,
in avoiding errors made by past language designers,
in evaluating alternative designs,
and in the detailed specification of your design.
Perhaps more important, if your design is to be heavily used,
you will need to know how to evaluate it,
and what trade-offs exist among competing goals.
Such justification of a design is a necessary step in convincing
yourself and others that your design is good (or bad).

Notations that are similar to programming languages
are found in every area of computer science.
Besides specification languages,
other similar notation systems include:
user-interfaces, program libraries,
formal models of computation,
database query languages, operating system command languages and system call
interfaces, mathematical logics, computer instruction sets,
expert system shells, network protocols, and many others.

In addition, language design is challenging.
Since it is one step removed from programming (you design notations
that are used by programmers to write many different programs),
the opportunities for good or ill are multiplied.
Because of that, it is great fun!

Knowing how to solve problems using the different paradigms
is important for several reasons.
You can find solutions to problems more surely if you have many different
ways to approach problems.
In the twenty-first century you will not necessarily be programming
in FORTRAN or C;
if you can program in a language such as
Smalltalk, C++, or Ada, or other new languages you will be much in demand.
As parallel programming becomes more important,
the use of functional and logic programming languages may increase.
Already the use of object-oriented languages is increasing.

Even if you do not become a programmer, the ideas of the functional
paradigm (function abstraction, infinite data structures, continuations,
referential transparency) have important applications in all areas of
computer science and in many other contexts such as mathematics
and engineering.
Similar comments hold true of the object-oriented and logic programming
paradigms.
For example, the idea of data abstraction
is certainly a key concept in software engineering and even in contemporary
mathematics (category theory).
Knowing logic programming can help you in such diverse tasks
as using a database query language
and in careful specification of problems
(which is necessary for problem solving in any domain).

Understanding the semantics of major features of programming languages
is necessary to use such features and to design new languages.
For example, if you want to program in an object-oriented language
you need to understand inheritance and message passing.
The better you understand such features, the better you will be able
to program, reason about, and debug your programs.
Formal methods (specification and verification)
are becoming increasingly important in day to day programming
at many companies,
and a deep understanding of the semantics of programming languages
is a great help in using formal methods.
Without understanding the semantics of such features,
you may also have difficulty discussing programming language ideas with others,
and will have difficulty in reading the technical literature.
If you are planning in specializing in some other area of computer science,
you may someday need to read some of the literature on programming languages,
either to use results from programming languages,
or to apply ideas from your area to programming language research.

Enrichment Objectives

Enrichment objectives could be multiplied endlessly.
Listed here are general statements of those that
I tend to teach or that you may wish to investigate.
The justification for each objective is included in this list.

Understand the goals and problems of language design,
the successes and limitations of historical approaches,
and current research directions in language design.

Understanding the history and the ``state of the art'' in programming
language design is important for the following reasons.
Knowing the history of language design will help you avoid mistakes
and can point out fruitful approaches to solving design problems.
Knowing the current research directions in language design
helps you avoid spending too much design effort on features that
are not well understood;
or if you are a programming languages researcher, it tells you places
to spend effort.
Knowing the goals and problems of language design also helps
you categorize problems that may arise in your own work
as being in programming languages or elsewhere;
this gives you a start towards looking for existing solutions.

Apply the techniques and results of language design
in other areas of computer science.

This goal may be important for doing successful research in other areas
of computer science.
Certainly much fruitful research in computer science happens at the boundaries
between different areas of computer science.
A few examples of interaction between programming languages and other
areas:
object-oriented databases, capability based operating systems,
formal language theory, reduced instruction set computers,
data flow computers, type theory, knowledge representation languages.

Understand how different approaches to parallel processing
can be reflected in programming languages.

If you are a programmer,
you will probably be programming on a concurrent computer or
writing distributed programs during your career.
If you are a theoretician,
you will surely spend much of your efforts thinking about
parallel processing.

In 1993 there were two course texts:
David A. Watt's
Programming Languages: Concepts and Paradigms
(Prentice Hall International Series, 1990),
with a supplement of Watt's
Programming Languages: Syntax and Semantics
(Prentice Hall International Series, 1991).