Programming Language Explorations
This text covers various programming language
concepts, including binding, scope, typing, parameterization, modularity,
concurrency, and metaprogramming—not with a list of explanations
of each topic, but rather within the context of whole-language overviews
containing plenty of runnable example programs. We aim to help developers
learn a bit of theory, and introduce students to a number of modern
languages. All of the source code for the book’s examples, as
well as number of bonus scripts, reside in
this GitHub repository.
Contents
- Chapter 0 Introduction
- A little on why the study of languages is fun and some hints about
what’s coming up in the rest of the book.
- Chapter 1 JavaScript
- A tour of one of the world’s most popular languages, introducing
assignment, references, shallow and deep copies, null and undefined, weak
typing, assertions, anonymous and higher-order functions, stack frames,
closures, static vs. dynamic scope, shallow vs. deep binding,
methods, prototypes, and asynchronous programming with both
callbacks and promises.
- Chapter 2 CoffeeScript
- A tour of a language that compiles to JavaScript, or as is sometimes
said, is JavaScript—though with an alternate syntax
(you’ll notice a lot less clutter). We take a first
look at destructuring and existential operators, and explore a very
interesting design decision that avoids shadowing almost everywhere.
- Chapter 3 Lua
- A tour of the well-loved lightweight scripting language behind
World of Warcraft and Angry Birds (among others), introducing
some new types, an approach to errors that avoids exceptions,
and a unification of arrays and dictionaries known as the table.
We also see metatables, which provide both differential inheritance
and operator overloading, and see coroutines for the first time.
- Chapter 4 Python
- Our first language with a complex type system: types
are first-class objects within the language and the programmer can
define new types. This chapter introduces supertype-subtype
relationships, multiple inheritance, keyword arguments,
pass-by-sharing, special methods, iterators and generators,
and decorators.
- Chapter 5 Ruby
- Object-orientation and much more within an overview of the language
billed as “A programmer’s best friend.” We define
messaging, encapsulation, class-based inheritance, and polymorphism, and look
at access controls and singleton classes. Ruby’s blocks and
mixins bring up some new issues, as does the language’s extensive
metaprogramming capabilities.
- Chapter 6 Julia
- A tour of the new dynamic language for scientific computing where
we encounter abstract types, parametric types, sum and product types,
and the notions of covariance, contravariance, and invariance. We see
polymorphism with multiple dispatch (which differs from the single-receiver
forms of previous languages), a metaprogramming facility with
hygienic macros, and language support for parallel and distributed
computing.
- Chapter 7 Java
- An exploration of our first statically-typed language with coverage
of classes, modifiers, interfaces, generics, optionals (and their
relationship to the billion dollar mistake), reflection,
and quite a bit about threads and synchronization.
- Chapter 8 Clojure
- A tour of the mostly-functional, modern dialect of Lisp, that
interoperates with Java. We look at its interesting syntax, its rich set of
data types, and its implementation of namespaces; then introduce persistent
data structures, transients, software transactional memory, and agents.
We look at two approaches to the expression problem (protocols and
multimethods) and discuss how Clojure’s hygienic macros compare
to Julia’s.
- Chapter 9 Elm
- An overview of the member of the ML-family of languages that
makes it fun to write reactive web clients in a functional style.
Our tour introduces the beautiful aspects of the ML-family—Hindley-Milner
typing with type variables and extensive type inference, pattern-matching,
and tagged union types—as well as Elm’s contributions, including
record types and subscriptions. This chapter (together with
the overviews of Haskell and Idris in Chapter 14) discusses the general problem
of managing side-effects in pure functional programming.
- Chapter 10 Erlang
- The language known for scalability and incredible seven-nines
availability that powers the messaging infrastructure behind Whisper and
WhatsApp. As Erlang is a functional language like Clojure and Elm (though
with a rather unique syntax), this chapter continues our discussion on
loop-free, matching-oriented programming with immutable data. We focus
on what makes Erlang Erlang: its messaging system based on processes
without shared memory, and its achievement of high availability
through a philosophy known as “Let it Crash.”
- Chapter 11 Go
- Another language emphasizing distributed programming via message
passing, but unlike Erlang, places the focus on channels rather than
on named processes. Our tour introduces a few other concepts,
such as multiple-value function returns, defer statements, explicit pointers,
slices, and panics. We examine Go’s level of type inference, which
falls somewhere in between Java’s and Elm’s.
- Chapter 12 Swift
- A look at the elegantly-designed, safe, fun, and powerful
modern language most often used for writing native applications in macOS,
iOS, tvOS, and watchOS. Here we see character processing done right,
common collections implemented as library types rather than hardwired
into the language (though with syntactic sugar to trick you), more on
optionals, custom operator definitions, extensions, and protocols.
We also spend time on the details of automatic reference counting (ARC).
- Chapter 13 Additional Languages
- Brief looks at Fortran, COBOL, Lisp, Algol, Simula, Smalltalk, C,
C++, Rust, CLU, Ada, C#, Scala, Bash, Perl, Standard ML, OCaml, Haskell,
F#, Idris, ParaSail, Chapel, Elixir, PHP, Hack, TypeScript, Dart, APL,
Prolog, K, Io, Factor, Brainfuck, Befunge, LOLCODE, and nasm (an assembly
language for the x86 architecture). This chapter is by no means an
afterthought or an aside; the sections on Rust and C, in particular,
discuss how one deals with explicit pointers without
a garbage collector, while other sections introduce new programming
paradigms not covered in the twelve featured language chapters.
- Chapter 14 Afterword
- A review of language concepts in a Socratic fashion.
- Appendix A Numbers
- Encodings of fixed-size integers and IEEE-754 floating point numbers.
- Appendix B Text
- All you need to know about Unicode (including what extended
grapheme clusters are, and how exactly UTF-8 works), and a
little bit more.
Good to Know
Some prerequisites: This book is not for beginning programmers. We
assume you know at least two languages pretty well, and hopefully a couple
more. You should know the basic concepts surrounding variables, expressions,
operators, functions, and basic data structures, and have experience
writing nontrivial applications—this book is a tour, not a
tutorial. We cover many interesting (and often powerful) features,
and purposely do so with code that is often very dense and sometimes
cryptic, even when presenting unfamiliar paradigms for the first
time. If you like to learn by reading example code, and
performing your own experiments, you should
find the approach to your liking.
Most of the code examples are written as their own unit tests,
which should help you learn the concepts as you read the code itself.
We favor this style over excessive commenting.
Uncle
Bob tells us why comments are not “pure good.”
Please note the book is not a treatise based on formal
syntax and semantics. For deeper theory, see, for example,
Harper,
Pierce, or
Turbak and Gifford.
Looking for more on history? Start with Wikipedia’s articles on programming language
history and follow links. Make sure to go way back and read some early papers;
the classics by
Knuth
and Kay are must
reads for anyone that appreciates and values where the field has come from.
Finally, for an approach to language practice and theory
organized around programming style and paradigms, don't miss
Lopes.
Additional Resources
We’ve put all of our examples, and unit tests galore, on
GitHub, of course.
The repo contains pointers to additional resources (books, papers,
applications, frameworks, etc.) for each of the
programming languages covered in their respective README.md files.
See something wrong or want to add anything? Send us a pull request.
There are, however, many resources not tied to any particular
language that you may enjoy. Here are just a few:
In addition, you might want to visit a few languages not covered in the book.
Here are some of our favorites:
Nile •
Scratch •
Snap! •
GP •
Ioke •
J •
Self •
Racket •
D •
Crystal •
Ceylon •
Kotlin •
Boo •
Zimbu •
Fantom •
Opa •
Vala •
GML •
PureScript •
Nim •
Nemerle •
Kitten •
Mercury •
Black •
Ciao •
Roy •
Ur •
Quipper •
Pure •
Quorum •
Falcon •
Q# •
TypeScript •
Zig
Just for fun, we’ve gotten started on a
little “browser” of language highlights for each of the
languages from the book and many others as well.
Updates
The languages covered in the book are evolving! Sometimes this means the text in the book goes out of date. We’ll do our best to keep with breaking changes and provide text changes and replacement pages here. Here’s what we know so far:
Changes to Ruby
Ruby 2.4 arrived after the book was first printed, and came with one welcome language change: the old Fixnum
and Bignum
classes are now unified into a single Integer
class. Fortunately the only page in the book dependent on this difference was page 80. Please download the updated page.
Changes to Swift
The first printing took place when Swift 3 was in beta. The release version of Swift 3 included significant language changes, requiring several scripts and a couple pages to be rewritten.
- Page 2, third script, and Page 258. Remove
combine:
in reduce
call.
- Page 244, second script. Replace
Process
with CommandLine
.
- Page 248, third script and Page 259, third script. Replace all uses of
M_PI
with Double.pi
.
- Page 253, second script. Replace
ErrorProtocol
with Error
, and make the same replacement in the text of line 3 of the following page.
- Page 255. The argument to
String()
must now be prefixed with describing:
.
- Page 254-256. The mechanisms for operator precedence have been drastically changed. Download replacement pages for the book.
Changes to the xregexp library used in JavaScript and CoffeeScript
Recent versions of the xregexp library now export the XRegExp
function as the module default, therefore:
- Page 25, second script. Remove
.XRegExp
near the end of the second line.
- Page 33, first script. Remove the braces around
XRegExp
in the second line.
- Page 44. Remove Exercise 2.19, which no longer applies, thanks to this library change.
Changes to Elm
The first printing of the book took place when Elm was at version 0.17. Recent language changes have been quite significant; for example, backticks to make functions infix are gone, apostrophes are no longer allowed in identifiers, the argument order for andThen
has changed, and range expressions such as [1..10]
have been removed from the language. More significantly, the elm-test
package has completely changed. We have decided to remove elm-test
assertions (and the dependency on this package) from our sample code and replace them with our own trivial assertions module.Because of these changes, the entire chapter has had to be rewritten. Download replacement pages for the book.
Changes to Julia
The first printing of the book took place when Julia was at version 0.4.0. Recent language changes have been quite significant.
- Pages 103-109. There have been changes to the type hierarachy. The types
ASCIIString
and UTF8String
have been removed. Array slicing of rows now produces vectors. The supertype of Set{T}
has changed. The function super
is now supertype
. Functions now have special types. Download replacement pages for the book.
- Page 114. RemoteRefs are now called Futures, and factoring is now part of a package, so we had to rewrite the scripts on the page. Download the replacement page.
Errata
Here are the outright mistakes in the printed text we know about that are not due to language evolution. Please let us know if you find anything. Email one of the authors or submit a pull request for this file.
- Page 27, fourth bullet in the Wrap Up section. Replace the words “and the empty object” with “and the value
false
itself.” Thanks to Damjan Vujnovic for discovering this error. (The empty object is definitely truthy in JavaScript!)
- Page 102, near the bottom. The Python interactive session was completely wrong. The use of the existing variable in the list comprehension (or equivalently, the “leakage” of the comprehension index variable) was a feature of Python 2 and no longer appears in modern Python (3+). We have replaced this example to highlight CoffeeScript instead, which does leak the comprehension index. Download the replacement page. Thanks to Edgar R. Chavez for discovering the problem.
- Page 221, line 2 of text. Insert and between creating and modifying.
- Page 221, line 5 of text. Remove the word more.
Additional Exercises
The text features 300 exercises, most of which are “further
explorations” in which you find or install compilers or interpreters,
investigate aspects of a language not covered in the chapter proper,
muse about language designers’ intents, and try your hand at
both large and small programming tasks. For those wishing more practice
or are looking to explore many programming language topics not covered in
the text, we’ve provided a page
with a few more.
If you are interested in some short language-specific questions
useful for training your short-term memory and reinforcing your
fluency with the material, we have hundreds
of these as well.