book cover
Additional Exercises

If you’ve found a passion—or enhanced your existing passion—for programming languages by working on the 300 exercises in the text, you might like to continue practicing your skills and even explore new topics we were not able to include in the printed book. So we’ve decided to put together a growing list of fun, interesting, and sometimes challenging problems here.

(If you’d like to contribute some of your own, please contact one of the authors or create a pull request.)

  1. Implement Kathi Fisler’s modification of the Rainfall Problem in as many languages as you can.
  2. In his Scrubbing Calculator essay, Bret Victor says “We are accustomed to assuming that variables must be symbols. But this isn’t true—a variable is simply a number that varies. If we are able to vary numbers interactively, then we don’t necessarily need to name them.” Read this essay (and the related Kill Math and Ten Brighter Ideas essays). Is it possible for a programming language to be defined in which variables are something other than named containers for values (or names bound to values)? Or must a language use symbols while scrubbing remains a technique relegated to the environment?
  3. What is flow typing (a.k.a. flow-sensitive typing)? What was the first language considered to employ this style? Which more well-known languages picked it up?
  4. What is gradual typing?
  5. Which languages, if any, employ shallow binding in lieu of deep binding? (These terms were defined in the JavaScript chapter.)
  6. Implement the three scripts that began each of the main chapters in the book (Triples, Anagrams, and Word Frequency) in Ceylon, Kotlin, and Scala.
  7. The first edition of the book focused entirely with text-based languages and thus left out discussion of visual languages such as Scratch and Snap. Implement the word frequency application in Snap.
  8. Investigate the language Forms/3. Work through the examples in the guided tour. Build a 10x10 “multiplication table” in the language.
  9. What is live programming? Does liveness apply to programming languages or just to programming? Do any languages advertise themselves as being more live than others?
  10. The language Subtext purports to be a “ongoing experiment in radically simplified programming...not a Domain Specific Language but rather a general purpose language designed from the ground up to make application programming radically simpler and easier.” Build a small application in Subtext. How does it differ from more conventional languages?
  11. We gave a brief mention and a short example program in GNU Smalltalk in Chapter 13. There exist several other Smalltalk dialects, of course. Implement the GNU example in Squeak.
  12. Much like the original language ML gave rise to what is now the ML family of languages, we now have a very large Lisp family. What are the characteristics of this family? What is the difference between a Lisp-1 and a Lisp-2? What are the major differences between Common Lisp, Scheme, Racket, and Clojure?
  13. Some type systems include a bottom type and a top type. What are these? Give examples of these in several languages which with you are familiar.
  14. What is a kind in type theory? Give an example in Haskell using kinds.
  15. Read Chris Smith’s What To Know Before Debating Type Systems. Why does the author argue that classifying type systems as “strong“ or “weak” is “unfortunate”? What, according to the author, are the characteristic aspects of static and dynamic type systems? How are they considered “completely different things”?
  16. Cardelli and Wegner’s 1985 paper refined Strachey’s distinction between parametric and ad-hoc polymorphism into a four-category scheme with parametric, inclusion, overloading, and coercion. Give examples of each in Java or C# (or any similar language). How would you classify Julia’s multimethods?
  17. Find at least three distinct, but relatively recent, definitions of the term object oriented. How do these differ from each other and from the original idea for which the term was coined? (Note that the fact the term has evolved over the years does not mean that modern usage is necessarily wrong.)
  18. The languages Go, Rust, Swift, Julia, and C# all have type systems with both signed and unsigned integers. Each language also features sequence types with a predefined length method (perhaps called len, length, size, or count). For each language, find out whether the length-determining method returns a signed or unsigned value. Why might a language designer choose to return a signed value?
  19. We covered both 32-bit (single-precision) and 64-bit (double-precision) floating point type in our appendix on numbers. However, some languages include minifloats, quadruple-precision, and octuple-precision floats. For each type, give the number of bits in the representation, as well as the largest possible representable value.
  20. Object-oriented programming languages have method dispatch as a primary concern. Usually dispatch is performed on the method receiver or on argument types, but dispatch on (arbitrary) predicates is also possible. Read Todd Millstein’s paper on practical predicate dispatch. Compare and constrast the paper’s JPred extension to Java with Erlang’s use of guards with pattern-matching.
  21. Read this short essay on functional vs. object-orientation. Summarize the main points of the essay.
  22. When, exactly, in JavaScript, must you call super in a constructor?
  23. This article on the continuing popularity of Fortran, features a few snippets of Fortran code for processing arrays in a syntax much more compact that found in C. Rewrite these examples in Julia.

Many more to follow.