Excellent textbook whose main message could be summarized as: Ada2005 is not your father's Ada83. Or Ada83 corrected and done right. Or perhaps by unstated-by-Barnes implication: C++ and Java done right, assuming an Algol68/Pascal syntax instead of C syntax.
For all practical purposes, this textbook assumes that you already know a non-Ada2005 object-oriented imperative programming lanugage, and that you are interested in learning Ada as an additional OO imperative programming langugage beyond the ones that you already know, such as Ada83, Ada95, Java, C++, C#, Objective C, Python, or Smalltalk. (Conversely, this textbook rarely mentions non-Ada2005 programming languages other than Ada83 and Ada95.) Hence it is not for true beginners who do not already know basic imperative or OO concepts, because practically no introduction of or justification of such basics is provided. Although, regarding the readers for whom syntax and semantics that generally correspond to other OO imperative programming languages is their primary interest, they will be exhilarated by Barnes' illumination of the orthogonality, tunability, and flexibility that Ada's syntax permits to go from highly-efficient hardware device drivers up through quite-sophisticated abstractions & enforcements (including now, in Ada2012, declaration of Eiffel-style invariants, which of course are absent in this Ada2005 textbook) when compared to nearly any other programming language: OO or imperative or generic or pure-functional or otherwise.
Conversely, this textbook (and the reason that I deducted one star) provides very few details regarding how the Ada run-time checks operate and only partially covers how the Ada compile-time checks operate. When writing programs in Ada, one must not only be thinking of the syntax, but of a more-elaborate semantics than is present in nearly any other programming language, because few other programming languages attempt to perform mostly a priori as elaborate of a proof-by-mathematical-induction of the correctness of the lifetime of memory allocation as Ada does. 1) A priori design of strong- versus weak-links in otherwise a posteriori smart-pointer synchronous garbage destruction in C++, 2) Ada's largely a priori proof-construction mostly at compile time for the compiler or runtime to overtly/synchronously know when the end-of-life occurs, and 3) the various flavors of asynchronous automatic garbage collection (AGC) in many programming lanugages are 3 competing schools of thought, where it is largely C++ versus Ada versus the rest of the imperative-programming world, so it is no trivial matter in learning Ada. Multiple times in this textbook, Barnes touches on this memory-allocation end-of-life topic with an it-just-works attitude without enumerating all the nontrivial subtleties (as the LRM and AARM do) that can precipitate the situation where the Ada compiler can emit a vast variety of compile-time errors that inform the programmer that the code's malformedness or sloppiness a) blocks incremental formation of the mathematical proof and b) hence likely has at least one bug.
On this topic of determining memory allocations' end of life, I do sympathize with the reviewer who instructed us all in effect: go read the freely-available-for-download _Ada Reference Manual_ (LRM) or better yet the freely-available-for-download _Annotated Ada Reference Manual_ (AARM) and to a lesser degree the freely-available-for-download _Ada Rationale_ to learn about how this proof-by-mathematical-induction is constructed. Although even in those references, the information is highly scattered piecemeal. I hope that the author will add a lengthy chapter on this topic in the next edition, because it *definitely* needs more illumination (without a programmer needing to slog through the 1,220-page AARM to interpret all the subtle nuances) for a programmer to understand all the compile-time errors regarding why the program is being rejected due to the compiler's incremental formation of this mathematical proof followed by the runtime's enforcement a posteriori of what the compiler could not accomplish a priori.