This textbook is intended as a guide for programming-language designers and users to better help them understand consequences of design decisions. The text aims to provide readers with an overview of the design space for programming languages and how design choices affect implementation. It is not a classical compilers book, as it assumes the reader is familiar with basic compiler implementation techniques; nor is it a traditional comparative programming languages book, because it does not go into depth about any particular language, instead taking examples from a wide variety of programming languages to illustrate design concepts. Readers are assumed to already have done at least a bit of programming in functional, imperative, and object-oriented languages. Topics and Suitable for advanced undergraduates and beginning graduates, this highly practical and useful textbook/guide will also offer programming language professionals a superb reference and learning toolkit.
This book was the textbook for a course I took in Programming Language Design lead by the author. While I aced the course, I'm not sure it was the book that enabled me to do it.
It covers a wide range of topics, from initial formalisms such as Turing machines and lambda calculus, over variable scoping, type systems, memory management, Turing completeness, and many other topics. Given how sweeping it is, I can't think of anything that it lacks, within its implied scope.
It's clearly a book about programming language design, so it's not too concerned about implementation details. Of course, some language design decisions impact how a compiler or interpreter is implemented. For example, if you decide to design a language with automatic memory management, you'll need to consider how to enable that in practice.
This is where I think it becomes somewhat uneven. It does get quite detailed when it comes to various strategies for garbage collection, almost to a point where it starts to look like a book on programming language implementation. Torben Ægidius Mogensen has a book about that, too, so this is hardly surprising. Still, other complex implementation strategies are discussed, but not shown in detail. As an example, I found the section on Hindley-Milner type inference hard to follow. Fortunately, after decades of F# and Haskell programming, I already have a good intuitive grasp of how type inference works in those languages, but I wonder how much the target reader gets out of it.
The treatment of Prolog, on the other hand, was quite interesting, and the chapter on semantics was also useful.
For someone like me, who have programmed for decades, it gives a good overview, and provides some missing pieces, but I still wonder how useful it is for the young undergraduate student.