Susan Harkins (263) [Avatar] Offline
#1
Please list errors you find in Groovy in Action, Second Edition in this folder. We'll compile and publish a comprehensive list for everyone's convenience. Thank you!

Susan Harkins
Errata Editor
364193 (1) [Avatar] Offline
#2
Hi ReGina Folks,

I have been avidly reading ReGina and enjoying it! The following items may be errata:

1) page 329, bottom line: (Remember: always before optimizing!) ... did you mean to say "Always profile before optimizing!" or something to that effect?

2) page 497, code snippet at top of page: def venue = marathon1.venue ... I don't see the marathon1 variable declared anywhere ... did you mean record1.venue?

3) pages 517-518, Table 14.6 title: "groovy.util.Nod" ... missing "e" in Node

Thanks,
Rodney Maxwell
David M. Karr (64) [Avatar] Offline
#3
You call it a "folder"?

In section 1.1.3, "Power in your code: a feature-rich language", the following example is cited:

println( [String, List, File]*.package*.name )

After the example it says:
... to emphasize that the access to package and name is spread over the list ...

This produces the following output:
[java.lang, java.util, java.io]

The funny thing is, the following produces the exact same output:
println([String, List, File]*.package.name)

It doesn't appear to be necessary to "spread" over package AND name, just package.
Mittie (397) [Avatar] Offline
#4
Hi Rodney,

1) page 329, bottom line: (Remember: always before optimizing!) ... did you mean to say "Always profile before optimizing!" or something to that effect?

Yes, that should have been: "always _measure_ before optimizing"

2) page 497, code snippet at top of page: def venue = marathon1.venue ... I don't see the marathon1 variable declared anywhere ... did you mean record1.venue?

I'll leave that one to Paul.

3) pages 517-518, Table 14.6 title: "groovy.util.Nod" ... missing "e" in Node

Yes, the "e" is missing.

Thanks a lot for your findings!
Dierk
Mittie (397) [Avatar] Offline
#5
In chapter 1 we are not giving all details or all possible (arguably better) variants. This is later explained in full detail in chapters 4 and 7. The purpose of the chapter 1 is to give some motivation and a first impression. In that sense, this is not really an erratum but by design. Whether the design is wise is of course debatable.

Thanks a lot for posting and enjoy the further reading
--Dierk
paul.king (6) [Avatar] Offline
#6
Glad you are enjoying it.

Yes, marathon1 should be record1 for the venue calculation (as you point out) and also on the next line (the when calculation).

Cheers, Paul.

364193 wrote:Hi ReGina Folks,

I have been avidly reading ReGina and enjoying it! The following items may be errata:

[...snip...]
2) page 497, code snippet at top of page: def venue = marathon1.venue ... I don't see the marathon1 variable declared anywhere ... did you mean record1.venue?
[...snip...]

Thanks,
Rodney Maxwell
David M. Karr (64) [Avatar] Offline
#7
In section 4.2.2, "Using list operators", there is the following callout (with one phrase bolded):
Avoid negative indexes with half-exclusive ranges

Ranges in List’s subscript operator are IntRanges. Exclusive IntRanges are mapped to inclusive ones at construction time, before the subscript operator comes into play and can map negative indexes to positive ones. This can lead to surprises when mixing positive left and negative right bounds with exclusiveness; for example, IntRange (0..<-2) gets mapped to (0..-1), such that list[0..<-2] is effectively list[0..-1].

Although this is stable and works predictably, it may be confusing for the readers of your code, who may expect it to work like list[0..-3]. For this reason, this situation should be avoided for the sake of clarity.


This seems to be saying that list[0..<-2] is the same as list[0..-1]. I tested this with a simple example:
def lst = [1, 3, 5, 7, 9]
println lst[0..<-2]
println lst[0..-1]

This prints this:
[1, 3, 5]
[1, 3, 5, 7, 9]


Is this callout trying to make some other point besides what I've read here?
David M. Karr (64) [Avatar] Offline
#8
In section 9.2.6, "Scripting support", there is the following text before the code sample describing the @ConditionalInterrupt annotation, with one statement bolded:
The way you specify the conditional interrupt is within a closure annotation parameter. You can reference any variable that’s in scope within this closure. For scripts, general script variables are in scope, and for classes, instance fields are in scope. The following listing shows a script that executes some work 1,000 times or until 10 exceptions have been thrown, whichever comes sooner.

Following this is listing 9.25, titled "Using @ConditionalInterrupt to set an automatic error threshold":
import groovy.transform.ConditionalInterrupt

@ConditionalInterrupt({ count <= 5 })
class BlastOff3 {
    def log = []
    def count = 10

    def countdown() {
        while (count != 0) {
            log << count
            count--
        }
        log << 'ignition'
    }
}

def b = new BlastOff3()
try {
    b.countdown()
} catch (InterruptedException ignore) {
    b.log << 'aborted'
}
assert b.log.join(' ') == '10 9 8 7 6 aborted'

The problem is, the description in the text does not describe what this code does. It causes the exception to be thrown when count reaches 5 or lower.


David M. Karr (64) [Avatar] Offline
#9
Figure 9.6, "Classes involved with the @Main local AST transformation", looks like this:

image

Assuming that a box "foo" with an arrow pointing to box "bar" with a notation "verb" on the arrow means "foo verb bar", then the arrow labeled "Implements" pointing from the box labeled "ASTTransformation" to the box labeled "MainTransformation" should be pointing in the other direction, as "ASTTransformation" is the interface being implemented by "MainTransformation".
David M. Karr (64) [Avatar] Offline
#10
Section 10.2.1, "Finding typos", demonstrates that the Groovy compiler doesn't detect a typo, unless you add the @TypeChecked annotation.

It might be worthwhile to mention that IDE support can mitigate the lack of a "@TypeChecked" annotation. For instance, in Eclipse, if you don't have the @TypeChecked annotation, it doesn't report an error for this test case, but it does underline the questionable variable reference. This might be enough to alert the developer of a misspelling.
David M. Karr (64) [Avatar] Offline
#11
In section 10.2.6, "Type checking closures", there is the following text, with my bolding:
Another alternative that the type checker can possibly use to determine argument type information is API metadata. Groovy has several annotations that add metadata to the API. Let’s look at those next.

@ClosureParams

Another alternative that the type checker can use to determine argument type information is API metadata, if it’s available. Groovy provides the @ClosureParams annotation as used in the following listing to give type hints for the expected parameter types of the validation closure.


Not an error, but I would imagine almost duplicating that same phrase so close to each other probably isn't optimal.
David M. Karr (64) [Avatar] Offline
#12
Following listing 10.43, "Immunity to monkey patching", there is the following text, with "(n)" to indicate what numbered marker the text refers to:
The first case(2) isn’t statically compiled, while in the other(2) we’re using @CompileStatic.


The marker reference for "The first case" is "2", but it should be "1".
David M. Karr (64) [Avatar] Offline
#13
In section 11.2.1, "NodeBuilder in action: a closer look at builder code", in the following footnote:
Because invoices is the root node, the method name makes no difference in how we use the node in the example. Listing 11.4 also works if you replace builder.invoice with builder.whatever.

Change "builder.invoice" to "builder.invoices".
David M. Karr (64) [Avatar] Offline
#14
Section 17.7, "Testing with the Spock framework", has a curious statement:
Also note that you can use spaces in the method name, a feature provided by Spock, which is implemented using an AST transformation.


There's no doubt that this is not "a feature provided by Spock", as you can do this in any old Groovy script or class. I have no idea why an AST transformation might be involved with this.
225036 (5) [Avatar] Offline
#15
Listing 9.12 Using @Delegate

Shouldn't the class NoisySet "implement Set"?
225036 (5) [Avatar] Offline
#16
225036 wrote:Listing 9.12 Using @Delegate

Shouldn't the class NoisySet "implement Set"?
[/quote

Just found further down that it does not have to implement the interface.
deisner (5) [Avatar] Offline
#17
In Listing 3.7, the following regular expression will not do what the comment claims:
// twister must contain only words delimited by single spaces
assert twister ==~ /(\w+ \w+)*/

Can you see the problem? Here's a hint: It will match "she sells some fresh tuna", but it will not match "she sells a fresh tuna".

The issue is that there is no white space between the repeated matching groups. So while the novice reader may naively think that the regex is matching
"she sells", "sea shells", "at the", "sea shore", "of seychelles"

what it's actually matching is:
"she sell", "s se", "a shell", "s a", "t th", "e se", "a shor", "e o", "f seychelles"

A better regex to match the comment's claim might be /(\w+ )*(\w+)/.


Lutz Adam (6) [Avatar] Offline
#18
Errata (typo) on page xxvii, line 6
... added chapter 19 "Concurrent Groovy with GPars" ...
must read:
... added chapter 18 "Concurrent Groovy with GPars" ...
Lutz Adam (6) [Avatar] Offline
#19
Errata (typo) on page xxxii, paragraph 2
JON SKEET Jon Skeet is a ...
must read:
JON SKEET is a ...
Lutz Adam (6) [Avatar] Offline
#20
Layout hint on page 70, table 3.5
The examples for Triple single/double quote would be more readable, if they where printed in several lines as in:

"""first $line
second $line
third $line"""
Lutz Adam (6) [Avatar] Offline
#21
Errata (typo) on page 73, last line
section D.2 of the cheat sheet ...
must read:
section D.1 of the cheat sheet ...
Lutz Adam (6) [Avatar] Offline
#22
Errata (typo) on page 84, line 16
line 3: twister =~ regexp (1) <- black bullet

line 7: twister = ~regexp

line 16: Note the different spelling in (1). This isn't a =~ b but a= ~b. Tricky.


line 16 must refer to line 7, not line 3.
Lutz Adam (6) [Avatar] Offline
#23
Errata (typo) in appendix C.1
downto/upto | Number, Closure | void

don't seem to belong to the primitive type boolean[], but to numeric or time primitive types.
Maybe the names of these types are missing in the leftmost column.