Programming is an activity and there is no doubt that (here as always) it's practice that makes perfect. Yet, as Michael Scott explains, there are reaProgramming is an activity and there is no doubt that (here as always) it's practice that makes perfect. Yet, as Michael Scott explains, there are reason you might want to have a closer look at your main tool, the languages in which you write your programs.
If you know the essential differences between different programming languages, you are in a better position to decide what best to use for a task at hand. Equipped with more technical concepts, you might find it easier to understand obscure features (like closures or the dereference operator) and learn new languages. With an idea about implementation details you might be able to assess performance trade-offs and make informed decisions about the design of extensive software projects.
For me personally it was an interest in the intricacies of language design that made me pick up this book. You might say I'm interested in programming languages as languages. I approached the book from the angle of computation linguistics, a field motivated by the belief that natural languages (like English or Turkish) are formal languages akin to programming languages, or can at least be described as if they were.
In more formal disciplines (like syntax or semantics), linguists make use of tools that originated or were first practically applied in computer science to define high-level programming languages. Because these languages resulted from conscious design and implementation decisions, they are freed from many of the complications that plague the study of real languages (like vagueness or ambiguity); as a result, it's probably easier to learn the relevant methodology in respect to the artificial languages and only later return to the real deal. Or at least so it appears from my laymen perspective.
Obviously, natural languages are implemented very differently in the human brain than programming languages are in the computer. Maybe this explains why I was less bothered about the implementation details that underlie design decisions and that are a main concern of the textbook. Of course, computer linguists use tools like scanners or parsers to generate language applications, but when it came symbol tables, registers, microprocessors, or the algorithmic definition of when an object is no longer useful (to be garbage-collected) I found myself skipping ahead. So, even to say that I've read only the core chapters – the chapters 1 to 10 – it would be an overstatement.
But even if you are only interested in the conceptual dimension of Programming Language Pragmatics, it's still a highly rewarding read. For instance, you might be surprised how much there is to learn about names and scopes. I'm sure I wasn't quite aware of the subtle differences between overloading (names can stand for different things in different contexts), coercision (the automatic converting of values from one type into another), and polymorphism (one and the same function allows for arguments of different times).
Variables too are deceptively simple. Yet, what they really are might be different from one language to the next, or even within a given language. Variables could be like boxes that contain values (the value model); or they might be references to values that (in a sense) live somewhere else in memory (the reference model). This distinction is related to other distinctions. For objects to exist, the computer needs to allocate memory. This is not a trivial matter, especially for data structures that can grow or shrink dynamically during runtime. The latter objects are created on the so-called heap, while objects of more primitive types live on the stack. A language like Java uses both; in some languages you can explicitly define variables to be of the one or of the other kind.
Similarly, there are different modes to pass objects as arguments into subroutines, namely call by reference, call by value, and even call by sharing. Speaking of subroutines, the author gives names for the two obvious kinds, i.e. the ones that return a value (functions) and the ones that do not (procedures). Throughout the book there are some occasions to introduce helpful terminology for familiar concepts. Additionally, footnotes point to inconsistent terminology between different languages. For instance, words like "functor" or "object" or "barrier" might mean different things for different people.
To better understand what's unique to given approaches, it's often helpful to contrast them with other options. The author gives illuminating examples from a vast variety of languages, very old (like Fortran) and newer (like Python) alike. There is also some attempt to explain why certain paths had been abandoned in favor of others, and why some approaches mark a clear progress over attempts of the past. For instance, it explains why `goto` statements are basically extinct today in favor of more structural concepts or why asynchronous events are now thread-based rather than based on coroutines and interrupts.
If you are motivated to really understand how compilers work and what makes different programming languages tick "under the hood", I'm sure you can spend months with this book. There are many exercises and suggestions for further research. If you want to pursue issues in even more detail, there are bibliographical notes that mostly point to the historical origins of now popular ideas. But even if you won't pursue all matters, Programming Language Pragmatics would be a great reference book even if you come across some interesting ideas in the future and you want to get some background. Not the least because of its very extensive Index.