CARVIEW |
Biography
Books
|
|
Reviews
Customer Reviews
Ruby in a Nutshell Review
2003-04-22 11:19:07
Paul R. Potts
Whoops, I promised in my review to provide an example of the issue that can arise in a case statement because: if a and b are not the same type, then "a === b" does not necessarily imply "b === a." This example is taken from Hal Fulton's book The Ruby Way.
<blockquote>
case /Hell/
when "Hello"
print "We matched.\n"
else
print "We didn't match.\n"
end
</blockquote>
As you might expect after that build-up, the code fragment above prints "We didn't match."
Ruby in a Nutshell Review
2003-04-22 11:01:20
Paul R. Potts
It is with considerable disappointment that I'm forced to report that Ruby in a Nutshell is the poorest book I've seen in the Nutshell line. To find out why, let's begin with the code sample on page 2. (I apologize for the lack of indentation in these samples; O'Reilly's site does not support using the HTML "pre" tag, so I'm using "blockquote" which does not preserve spaces; also, it seems to translate paragraph breaks into real "br" tags, unlike some sites).
<blockquote>
ary = [1,2,3,4,5]
ary.each do |i|
puts 1*2
end # prints 2,3,4,8,10 for each line
</blockquote>
Not only is the comment wrong (this example should print 2, 4, 6, 8, and 10, once each), but the code has a bug: the puts statement contains a "1" instead of an "i." That's not inspiring: I'm not sure who to blame, but clearly the editors or technical reviewers did not try the code samples as printed. Let's go on to the next example:
<blockquote>
ary = [1,2,3,4,5]
ary = ary.select do |i|
i %2 == 0
end # returns array of even numbers
</blockquote>
This example also fails! Why? Because Ruby is sensitive to whitespace in certain constructs: the lack of a space between the "%" and the "2" causes trouble. That's two critical typos in two brief examples: not a promising start! Let's move on to the next example:
<blockquote>
begin
f = open(path)
rescue
puts "#{path} does not exist."
exit 1
end
</blockquote>
This example does not execute, because "path" is undefined. That's a trivial omission, obviously, but again it indicates that no one bothered to make these short examples runnable. That's disappointing.
The next example shows how to use a network socket to retrieve the time:
<blockquote>
require "socket"
print TCPSocket.open("localhost", "daytime").gets
</blockquote>
This also does not work on my system (running MacOS X). The reason is because my system is not running an appropriate server; I know that, but if I was more of a novice, I might have given up Ruby in disgust by this point (on page 3), mistakenly blaming the language or library implementation. Given that Yukihiro Matsumoto is the author of Ruby, that's obviously not a desirable outcome.
Keep in mind that we are on page 3 of this book, in the introduction, under a heading entitled "Ruby's Elegance." This Nutshell book is clearly not intended as a beginner's tutorial, but does this principle make it acceptable that four of the five code samples in this section do not run as presented? I don't think it does. I think this is just the first warning indication of the disastrous lack of quality in this book. The introduction trails off with a few additional examples, including a minor variation on the socket example already presented and a redundant example of exception handling, but with no further commentary. This entire introductory chapter seems not to whet the appetite to learn Ruby as much as ruin it. However, let's press on and see if it gets better.
The book is quite short (with 204 numbered pages), and that's good. I like short books; as the introduction to Kerninghan and Ritchie's widely-known book The C Programming Language says, a small language "is not well served by a big book." The second chapter, "Language Basics," weighs in at just 30 pages. But it turns out that it isn't the length, it is the organization and presentation of the content. The other Nutshell books do it well; Kerninghan and Ritchie's book does it well. Ruby in a Nutshell does not.
The chapter begins with a description of the command-line options to the Ruby executable and a list of the environment variables that Ruby recognizes. These things would be more properly placed in an appendix devoted to the implementation. We are now left with just 27 to pages to cover the core language. Let me point out a few specific examples that show how the text veers off track.
Under the heading "Literals" and sub-heading "Numbers," we are shown the examples "123," a decimal number, "0377," an octal number, and "0xff," a hexadecimal number. So far, so good. But included in the list is "1_234," listed as "decimal with underline." What does this mean? What is the purpose of writing a decimal number with an embedded underline? (No mention is made of "underline" or "underscore" in the index, and the text offers no clue). That's a very minor example, but it is telling.
Under "Strings," we're shown the difference between double-quoted and single-quoted strings. On the very next page, though, we see an example of a string in backquotes. No mention is made of backquotes in the index, and backquoted strings are never explained. This is a Nutshell book, not a pocket reference: some explanation should be given of distinct language elements like this!
I've programmed in Scheme and other languages that support a symbol type; I thought I knew what a symbol was. Under "Symbols," we read that "A symbol is an object corresponding to an identifier or variable." In fact, that's false. A symbol never corresponds to a variable. A symbol is generally made of a string, hashed to a unique object, and usable as a distinguished value. We are shown two examples: ":foo" is described as "symbol for 'foo'." ":$foo" is described as "symbol for variable '$foo'." What this really means is that the first symbol is constructed out of a plain identifier, and the second out of a variable name. Any string can be used to generate a symbol using the Intern method; including a mention of that method here would reassure the user that symbols in Ruby work pretty much like symbols in other languages that support them. Instead, the book is riddled with bizarre and confusing terminology. Matsumoto may not be a native speaker, but he credits editors and reviewers; were they asleep on the job?
On page 16 under "Assigment," we read "The following elements may assign targets." What does that phrase mean? What is an "element?" Why was this text not turned into something more clear, using standard terminology? Under "Operators," we read "most operators are in fact method calls." Then, three lines later, we read "Most operators are actually method calls." Why was this redundancy left in place? Copy-editing should have caught this; this book is very, very poorly edited.
On the next page, under "Range operators," the description of the form "expr1 ... expr2" is "Evaluates expr2 on the iteration after expr1 turns true." Range operators are incredible useful and clever; it is a shame that anyone reading this description will be unlikely to gain any insight into how to use them. In a sidebar on special versions of methods that have "!" or "?" appended (in the Lisp world, methods ending in "!" are generally known as destructive, and methods ending in "?" are generally known as predicates), we read "A question mark ? is appended to a method that determines the state of a Boolean value, true or false." Why wasn't this convoluted sentence edited to say "method that returns a Boolean value?" In the next sentence, we learn that "Attempting to call a method without specifying either its arguments or parentheses in a context in which a local variable of the same name exists results in the method call being interpreted as a reference to the local variable, not a call to the method." This sentence needs at least six prepositional phrases to tell us that a local variable with the same name as a method can shadow the method, if the method call is ambiguous; an brief example here would be worth far more than this convoluted description.
As a further case study, let's take a look at the presentation of one more language construct: Ruby's version of C's switch, in Ruby called case. There are a few key points to keep in mind about the way Ruby implements this construct. The first is that there is no default fall-through, as in C and C++, and hence no need for break statements -- in fact, break may not be used here. The second is that the clauses are evaluated in the order given: this can be important, since clauses may overlap (for example, if they use ranges). The third is that to determine if a clause matches, the "===" operator is used, in a less-than-obvious way (briefly, if a and b are not the same type, then "a === b" does not necessarily imply "b === a." I'll show an example of this later).
Any Ruby reference worth the name should mention these three key points. In Ruby in a Nutshell, we are given a BNF skeleton (it is not quite real BNF, though) and a few lines of description. The lack of default fall-through is not mentioned. The use of "===" is mentioned, but without any detail. The fact that Ruby always evaluates the cases in the listed order is not mentioned. As far as I'm concerned, this presentation of the case statement is close to useless; it could serve to remind someone who already knows Ruby of the syntactical form, like a pocket reference card, but gives almost nothing of the distinguishing semantics for a programmer coming from another language.
I want to look at one more example: the use of while and until as statement modifiers. This is a clever little language feature that lets you write code like this:
<blockquote>
greeting = true
print "Hello\n" while greeting
</blockquote>
The above code will say "Hello" forever, while this version:
<blockquote>
greeting = false
print "Hello\n" while greeting
</blockquote>
never says "Hello." It is a somewhat non-obvious detail that when you use while as a modifier at the end a single statement, the condition is evaluated first. This runs contrary to C's do loop form. You can also use while at the end of a block of code:
<blockquote>
greeting = false
begin
print "Hello\n"
end while greeting
</blockquote>
but in this case, "Hello" will be printed once; the block is executed once before the condition is evaluated, just like C's do loop.
It is important to me that a book on Ruby should make a clear distinction between these two modes of behavior; Ruby in a Nutshell fails to clearly differentiate the behavior of the single-statement form. Instead we get the terse description "executes code while condition is true" for the single-statement form, and this awful sentence for the second: "If a while modifier follows a begin statement with no rescue or ensure clauses, code is executed once before conditional is evaluated." It is probably technically correct, but at this point in the exposition, it does not clarify anything to bring in rescue and ensure without further elaboration.
Although not billed as a tutorial, by comparison, Python in a Nutshell devotes 39 pages to the Python language, and the chapter is immeasurably more readable and more complete. It is also possible to divine all the tricky parts of Java from Java in a Nutshell; I refer to this book frequently when I've forgotten a detail about, say, inner classes. That just doesn't seem possible with this book. Is this because Ruby is so irregular, with an enormous number of special "quirks?" I don't believe so; Python and Java are certainly "quirky" in places as well (just look at the semantics of bindings from within nested scopes in Python, or the syntax of anonymous inner classes in Java). In a language guide, though, it is essential that any irregular semantics be clearly pointed out, and Ruby in a Nutshell doesn't do this well.
The remainder of the book covers the built-in library (built-in to the interpreter), and the standard library (defined in separately importable modules). This material looks concise (in fact, too concise). For example, suppose I wanted to fix the example given above:
<blockquote>
require "socket"
print TCPSocket.open("localhost", "daytime").gets
</blockquote>
On page 113, we can find the entry for TCPSocket. It is less than a page in length, and most of the entry is taken up by a longish piece of sample code, and most of that sample is scaffolding. (Again, it isn't the space used, but how it is used). The sample code uses the spelling TCPsocket (note the altered capitalization: another typographical error, but fortunately names in Ruby are not case-sensitive). The example also uses ARGV and thus, as far as I can tell, can't be executed using irb (the command-line Ruby interactor). It uses two additional methods on TCPsocket: addr and peeraddr, but these are not listed in the class methods. It turns out the methods are part of IPSocket, which is the superclass of TCPSocket, so I turned to the entry on IPSocket. The example given for IPSocket is actually an example of how to use TCPSocket (this time with the expected capitalization). This example succeeds in opening an HTTP connection to www.ruby-lang.org. It works, and that's a start, but it's too late to do much to enhance my opinion of Ruby in a Nutshell. It doesn't have to be this way. By comparison, take a look at Hal Fulton's The Ruby Way and the Pragmatic Programmer's guide, which features an excellent reference section with very brief, usable examples that can be tested interactively.
I hope that O'Reilly will do better in a later edition. Meanwhile, I can't recommend this edition to anyone, beginner or experienced Ruby user alike.
Ruby in a Nutshell Review
2003-02-25 18:09:29
Kenneth Wilcox
I was kind of disappointed with this book. Don't get me wrong, this book is well written has great documentation on the language basics, built-in functions and the Standard Library. From a dictionary perspective this is great for a reference. Since it is the only Ruby book published in English by O'Reilly I was hoping for more. For Example, a longer chapter on how to write Ruby programs. The introduction was a meager 4 pages. If you already know Ruby this may be a useful book, it you want to learn Ruby you'll have to look elsewhere.
Ruby in a Nutshell Review
2002-12-01 04:18:21
Björn Breitgoff
Ruby in a nutshell is compact and complete.
It doesn't waste lines on lengthy discussion but presents you
the raw facts. Each function of the language with a line of
description or seldomly more. Thats cool.
But I have to agree that a alphabetical lookup would have been
a huge improvement.
Ruby in a Nutshell Review
2001-12-17 08:38:59
Wayne Conrad
The subtitle is "A Desktop Quick Reference," but the classes aren't listed in alphabetical order. For me, this makes the "Quick" part of the title a lie -- If I have to look the class up in the index first, it's not quick. This flaw prevents "Ruby In a Nutshell" from unseating Dave and Andy's "Programming Ruby" as the definitive English-language reference for Ruby.
Ruby in a Nutshell Review
2001-12-11 05:12:23
Walid Shaari
Nice neat book, not what I expected to have when it mentioned that it was a nutshell, but fast read, nice organiztion, and lovely langauge to learn. you still need to refer back to the online documentation, and other books may be :)
Media Reviews
"This is an essential, concise desktop reference to Matz's free, object oriented Ruby language."--Martin Heller, Byte.com, March 11, 2002
Buy Direct and Save
Buy 2 Books,
Get the 3rd FREE!
Use discount code "opc10"
All orders over $29.95 qualify for free shipping within
About O'Reilly | Contact | Jobs | Press Room | How to Advertise | Privacy Policy
© 2008, O'Reilly Media, Inc.
All trademarks and registered trademarks appearing on oreilly.com are the property of their respective owners.