By Developers, For Developers

Historical errata for Getting Clojure

PDF PgPaper PgTypeDescriptionFixed onComments
184177TYPO

“To see get a feeling for how spec works” probably should be “To get a feeling for how spec works”

2018-01-31
187180TYPO

“Note that there is something a bit odd going on with the keys function: we supplied namespace-qualified keys in the spec: it’s :inventory.core/:title not :title.”

The namespaced keyword “:inventory.core/:title” has two colons.

2018-01-31
194187TYPO

“You can other interesting specs in clojure.specs.alpha3, which contains the specs for Clojure itself.” perhaps should be “You can see other interesting specs in clojure.specs.alpha3, which contains the specs for Clojure itself.”

2018-01-31
9ERROR

If println puts spaces around arguments, how come the output isn’t shown as
“Welcome to Clojure !”

2018-01-31
25TYPO

“with the less-than-enlighting name”

A typo in the word “enlightening”.

2018-01-31
73TYPO

Staying out of trouble section…

’“A downside of immutable lists and vectors is that it tends to cause disquiet in the hearts new Clojure programmers”

=>

“A downside of immutable lists and vectors is that it tends to cause disquiet in the hearts of new Clojure programmers”

2018-01-31
xiiiTYPO

The bullet point on destructing seems to be missing a word. The text: “…a feature that you can use dig your data…” Maybe it was meant to read like so: “…a feature that you can use [to] dig your data…”

2018-01-31
4633TYPO

> (def db (def db {:dbtype “derby” :dbname “books”}))

Double def.

2018-01-31
5441ERROR

(if ‘{:full :list} (println “So is a full list!”)) should be (if ’(:full :list) (println “So is a full list!”))

2018-01-31
89TYPO

page 89 of epub version…

There is a change of function name between ‘shipping-charge’ and ‘shipping-cost’

I suspect it should all be the former?

2018-01-31
184TYPO

> Since there is can be a significant performance
Since there can be a significant performance

2018-02-03
184SUGGEST

The fact that spec-based argument checking can introduce a performance penalty is introduced twice on the same page. Make this point only once, or have the second reference build on the first?

“Since there is can be a significant performance penalty involved in checking arguments, by default the checking is disabled.”

“Note that this spec-based argument checking can be a significant performance drag — consider that in our example, each book in the inventory is validated, even if the inventory is 20,000 books long — and so it should only be enabled during development and testing.”

2018-02-03
196TYPO

This feels like a typo:

> Clojure atomically imports java.lang into all namespaces
Clojure automatically imports java.lang into all namespaces

2018-02-01
198TYPO

Missing capitalization of Java:

> So in the same way we can call java methods on instances
So in the same way we can call Java methods on instances

2018-02-01
111TYPO

“Well round the chapter out …”

We’ll round the chapter out …

2018-02-03
108TYPO

“[…] we will take a look a unifying idea in Clojure.”

we will take a look at unifying idea in Clojure.

2018-02-03
106TYPO

“You can call you namespace whatever you want […]”

You can call your namespace whatever you want

2018-02-03
37ERROR

“You can also add the optional second expression inside of your if, giving you the classic if/then/else expression, sans the else keyword:”

I believe it is the optional third expression, counting the condition (which the initial description appears to do).

2018-02-03
38TYPO

“The other half is being able [to] ask the questions that evaluate to a boolean.”

2018-02-03
41TYPO

​ (​ if ​ ’{:full :list} (println ​ “So is a full list!” ​)) All the if expressions above will produce some output.

That’s not a list, but a map.

2018-02-03
127TYPO

(def scary-animals [“Lions” “Tigers” “Bears”])
;; Gives us (“Lions” “and” “Tigers” “and” “Bears”)
;; On my!
(interpose “and” scary-animals)

Interpose should be 2nd line not 4th

2018-02-03
11TYPO

Acknowledgements, 1st paragraph, 2nd sentence: “… and everyone who as ever …” => “… and everyone who has ever …”

2018-04-06
474ERROR

Actual:
(​defn​ n-gt-10-lt-100 [n]
​ \t (s/and number? #(> n 10) #(< n 100)))

Expected:
(def n-gt-10-lt-100
(s/and number? #(> % 10) #(< % 100)))

Explanation:

by using it with s/valid? i’m expecting such result:

(s/valid? n-gt-10-lt-100 99) -> true
(s/valid? n-gt-10-lt-100 100) -> false

2018-04-06
492ERROR

Actual:

(defn check-return [{:keys [args ret]}]
(let [author (-> args :book :author)]
(.indexOf ret author)))

Expected:

(defn check-return [{:keys [args ret]}]
(let [author (-> args :book :author)]
(if (not (empty? author))
(pos-int? (.indexOf ret author))
true)))

;; or

(def not-empty-string? (s/and string? #(not (empty? %))))
(s/def ::author not-empty-string?)

(defn check-return [{:keys [args ret]}]
(let [author (-> args :book :author)]
(pos-int? (.indexOf ret author))))

Explanation:

:fn function should return true or false value,
all values different than nil or false are taken as “truthy”

2018-04-06
83TYPO

Reference to Incanter project is spelled “Incantor”: “For a truly imposing example of a let, we need to look no further than this,
from Incantor”

2018-04-06
70DEFER

It might be good to mention that nested function literals will give error message that confuse a novice (or a master, at first). A long function literal (like in a generator?) might tempt one to use another function literal inside.

It's a good point, but I think it will need to wait until the next edition.
88SUGGEST

In the .epub version of the book as displayed on Google Books, the illustration in the section “Bindings Are Things Too” comes out as four almost featureless black boxes. I have no way to send a screenshot with this, but will DM one to the author.

2018-04-06
173TYPO

This test may not seem impressive, but get it to run and you have demonstrated that:
• There is a namespace called inventory.
• There are no gross syntax errors in inventory.

Well, I think that’s “inventory.core”, here and in the next item (which mentions “the inventory namespace”, too).

2018-04-06
178DEFER

“Note also that while clojure.spec is well integrated with Clojure, it is
delivered as a separate library. Thus if you are using Leiningen
you will need an additional dependency entry in your project file.”

It looks like the spec (alpha) jar files are automatically included without adding them as dependencies in project.clj, at least when using 1.9.0. I’ve pared down my profiles.clj and the libraries are still available and clojure.spec.alpha can be required without issue.

I think I'm going to leave this as is given that at least for a while people will be using various versions of Clojure.
185TYPO

“All we need is another spec namespace, clojure.spec.test.alpha and the check function it contains:”

better would be

“All we need is clojure.spec.test.alpha again (the same namespace that contains the `instrument` function) and the `check` function it contains:”

2018-04-06
205TYPO

Section: …And Great Responsibility
(def fav-boo “Jaws”)
(defn make-emma-favorite [] (def fav-book “Emma”))
(defn make-2001-favorite [] (def fav-book “2001”))

The initial `def` is for `fav-boo`, later names are `fav-book`

2018-04-06
155144TYPO

para 1 line 2: painter and the value associated :writer to writer .
should be: painter and the value associated :novelist to writer .

2018-04-06
165155TYPO

after first paragraph:
(class watson-1) ; user.FictionalCharacter
(class watson-1) ; user.SuperComputer

should be:
(class watson-1) ; user.FictionalCharacter
(class watson-2) ; user.SuperComputer

2018-04-06
176167TYPO

Second sentence under Testing Namespace and Projects:
clojure.test provides the run-test function
should be:
clojure.test provides the run-tests function

2018-04-06
177168TYPO

first line:
Call run-test without any arguments
should be:
Call run-tests without any arguments

2018-04-06
180171TYPO

last paragraph before “Staying Out of Trouble” has an s in front of ‘with’:
and combine it swith state-ments about properties
should be:
and combine it with state-ments about properties

2018-04-06
233227TYPO

In the third documentation line of start-samples:
fn is called to ensure that they’re all started in sync

the “re” of they’re is italicized

2018-04-06
253249TYPO

Throughout the examples on this page:
zero? is getting ~n instead of ~zero
which yields 100 in the expansions instead of 0

2018-04-06
227TYPO

> " agent it there "
Should be " agent is there"

2018-04-06
159TYPO

> “you may just find they maps and functions are enough.”
Should be “you may just find that maps and functions are enough.” (“that” instead of “they”)

2018-04-06
117ERROR

The text says that the “some” function returns the first item matching the predicate function or nil if no item found.

By playing with the example, I verified that “some” does not return the first item: it returns either true or nil.

2018-04-06Almost! some returns the value from the predicate or false. But good catch, thank you.
179ERROR

This function did not work for me:
(defn n-gt-10-lt-100 [n] (s/and number? #(> n 10) #(< n 100)))

When I removed the argument n and changed the n to %, the function did work. Using Clojure 1.9.0 and spec-alpha that came bundled with it.

22TYPO

In the “How Many Slots?” info box:

“This enables the count function do its thing…” should probably be
“This enables the count function to do its thing…”

51TYPO

The print-any-args function is defined as (defn print-any-args [& args] (println “My arguments are:” args)) and the console output I see for invoking (print-any-args 7 true nil) is “My arguments are: (7 true nil)”. However, the text states the output as “My arguments are as follows: (7 true nil)”. Perhaps the words “as follows” were included in a beta version of print-any-args.

89ERROR

The redefinition of compute-area as (defn compute-area [diameter] (* PI radius (/ diameter 2.0))) gives me a compiler error: “Unable to resolve symbol: radius in this context”. The following change works for me: (defn compute-area [diameter] (let [radius (/ diameter 2.0)] (* PI radius radius)))

30ERROR

In the sidebar “Associative Vectors” it is stated that dissoc works on vectors. I do not think that this is correct.

user=> (dissoc [0 1 2] 1)

java.lang.ClassCastException: clojure.lang.PersistentVector cannot be cast to clojure.lang.IPersistentMap

121TYPO

Overly nit-picky, but something I noticed immediately and got distracted enough to report it.

The bottom of the page contains this code:

;; And we have a classic!
(if (re-matches re title)
(println “We have a classic!”))

There are two spaces between “re-matches” and “re” instead of one.

155TYPO

The book includes the following code when discussing the instance? function:

(instance? FictionalCharacter watson-1) ; True.
(instance? SuperComputer watson-2) ; Nope.

I believe the comment “Nope” should be “True” because both expressions evaluate to true. The corresponding unit test in the sample code also appears to expect true for both expressions.

153TYPO

The book states that:

(def watson (->FictionalCharacter “John Watson” “Sign of the Four” “Doyle”))

“… gives you back a new record instance, which will print in the REPL like this:”

#records.core.FictionalCharacter{:name “John Watson”, :appears-in “Sherlock Holmes”, :author “Doyle”}

However, I get a different value for :appears-in when I evaluate “watson”:

#brews.scratch2.FictionalCharacter{:name “John Watson”, :appears-in “Sign of the Four”, :author “Doyle”}

153SUGGEST

The beginning of the page defines “watson” as:

(def watson (->FictionalCharacter “John Watson” “Sign of the Four” “Doyle”))

Then, in the “Records Are Maps” section, the book demonstrates using assoc:

(def specific-watson (assoc watson :appears-in “Sign of the Four”))

“specific-watson” doesn’t seem to be any more specific than regular ol’ “watson”.

Perhaps regular ol’ “watson” was intended to be defined like this:

(def watson (->FictionalCharacter “John Watson” “Sherlock Holmes” “Doyle”))

which would also address erratum #83171.

157TYPO

The following straddles pages 156-7:

“Each method needs to have at least one parameter, the record we’re operating on, which is conventionally called this. If you happen to have more than one this parameter—as we do in the greeting method in the preceding example—then this must be the first parameter.”

Perhaps the phrase “more than one this parameter” should be “more than one parameter”.

If not then I’m very puzzled by the concept of multiple “this” parameters.

161TYPO

Near the bottom of the page:

“Run the preceding code, and you will end up with value in test-component that
implements Lifecycle.”

should probably be

“Run the preceding code, and you will end up with a value in test-component that
implements Lifecycle.”

168TYPO

In the third paragraph below the “Property-Based Testing” heading:

“… along with a description of the of input data for which that property should hold.”

should probably be:

“… along with a description of the input data for which that property should hold.”

170TYPO

At the top of the page, the book states:

“For this we can use element (which will pluck a random element out of a collection) ….”

However, the subsequent code sample uses “gen/elements”, not “element”.

The code sample appears to agree with the documentation for clojure.test.check.generators.

168TYPO

Near the top of the page, the provided output of running “lein test” is stated as:

Ran 1 tests containing 1 assertions.
1 failures, 0 errors.
{:test 1, :pass 1, :fail 0, :error 0, :type :summary}

The result indicates one failure but the summary map indicates no failures.

211TYPO

The penultimate paragraph on the page begins with “The first thing to note is that all of this code, from our trivial book-store application down to the deep plumping of Compojure, ….”

The notion of Compojure having a high quality skin care regimen is certainly intriguing, but I suspect “plumping” should instead be “plumbing”.

215SUGGEST

The “State” chapter kicks off with the premise of counting the number of visitors to a web site and giving congratulations at designated count values. However, as the text progresses, the criteria changes from the 500th visitor, to every 100th visitor, and back to just the 500th visitor.

If there’s a reason for changing the criteria along the way then I’m afraid I’m too dense to detect it.

My humble suggestion is to commit to a single premise in order to avoid distracting the reader from the main point of the corresponding text: how atoms work.

67TYPO

line 7
need to replace from “Welcomes Dolly to Blotts Books”
to “Welcomes to Blotts Books Dolly”

73TYPO

Wrong function name in text:
“…replacing the recursive call to sum-to-n with recur”
Should be:
“…replacing the recursive call to sum-copies with recur”

180ERROR

Running “(s/explain n-gt-10 1)” does not produce the output given in the book (“val: 4 fails predicate: (> % 10)”). Either the output should be changed to “val: 1 fails predicate: (> % 10)” or the sample should be changed to “(s/explain n-gt-10 4)”.

75TYPO

“In fact, take out the [printf]s that we’ve sprinkled here and there,”
should be
“In fact, take out the [println]s that we’ve sprinkled here and there,”

73SUGGEST

I’d like to suggest transposing the parameters of the ‘wrap-logging’ function from [msg handler] to [handler msg].

Specifying the handler as the first parameter appears to be the convention for Ring middleware wrapper functions. Also, the thread-first macro ‘->’ seems to be used often when applying wrappers but the ‘wrap-logging’ function in its current state wouldn’t be able to participate.

Speaking of the threading macros, perhaps introducing them here instead of on page 123 would be worthwhile, that way the various ‘app’ functions on page 74 could be defined with less nesting, e.g.,

;; apologies for indentation mangling
;; book version
(def app
(wrap-logging
“Final response:”
(wrap-content-type
(wrap-logging “Initial response:” handler)
“text/html”)))

;; proposed version
(def app
(-> handler
(wrap-logging “Initial response:”)
(wrap-content-type “text/html”)
(wrap-logging “Final response:”)))

As someone coming from a servlet background, middleware and wrappers were completely new to me. Personally, I had a bit of trouble grasping the concept because I think I was spending extra brain cycles unpacking the ‘app’ definitions and getting a bit confused along the way.

234TYPO

“…we’ll return :completely[ ]confused.”
Should be:
“…we’ll return :completely[-]confused.”

96ERROR

Thus every def and defn that we have evaluated so far—with the example of
our file-based project back in Hello, Clojure—has gone straight into the user
namespace.

“with the EXAMPLE of our file-based project” should probably be “with the EXCEPTION of our file-based project”.

116TYPO

They then do their thing using only first , rest , and cons ,
or using functions that rely on the magic foursome.

“the magic FOURSOME” should probably be “the magic THREESOME”

133SUGGEST

The first element will be realized when calling my-repeat. Moving cons inside lazy-seq would solve this.

(defn chatty-identity [x]
(println “Hi there!”)
x)

(defn chatty-repeat [x]
(cons (chatty-identity x) (lazy-seq (chatty-repeat x))))

(defn lazy-chatty-repeat [x]
(lazy-seq (cons (chatty-identity x) (lazy-chatty-repeat x))))

(def oliver (chatty-repeat “Oliver Twist”)) ; Hi there!
(def oliver2 (lazy-chatty-repeat “Oliver Twist”)) ; Silence

152ERROR

(defrecord FictionalCharacter[name appears-in author])

Missing space between name and fields.

169TYPO

and all the other basic Clojure values with names like int , pos-int , Boolean ,
and keyword

“Boolean” should be “boolean”.

182TYPO

To turn the argument checking on we to need require yet another namespace:

“we TO need” should be “we need TO”.

203TYPO

As we saw in back in Chapter 8, Def, Symbols, and Vars

“saw IN back in Chapter 8” should be “saw back in Chapter 8”.

22ERROR

“On the other hand, adding a new item to the end of a vector can be quick if there happens to be room at the end of the block of memory.” is misleading because this alleged room at the end (also illustrated as “Extra Space” on the previous page) simply does not exist in the implementation of PersistentVectors. The text seems to describe a mixture of PersistentVector and TransientVector.

28TYPO

The first “to” in “whether you want to your logger to include the :debug information” does not belong there.

56TYPO

The first paragraph ends in “replacing the recursive call to sum-to-n with recur”, but the function’s name is actually sum-copies, not sum-to-n.

32ERROR

In this context, the word remove means…
“remove” should be “disj”.

9999ERROR

I entered a nonsensical page number because I am reading the book on Safari Books Online, and have no way to knowing either the PDF or the page number.

In Chapter 8 at the end of the ‘Symbols Are Things’ section, the book says:

“Being a value also means that a symbol can exist on its own,without being bound to another value.You can, in fact, make stand-alone symbols as fast as you can type,so that ’some-other-symbol and ’still-another-symbol are perfectly good expressions, even if neither symbol has ever appeared in a def.”

However when I try typing a symbol into the REPL, I get this error:

user=> ’some-other-symbol
Syntax error compiling at (REPL:0:0).
Unable to resolve symbol: ’some-other-symbol in this context

167155ERROR

The code “(instance? SuperComputer watson-2)” should return true, instead of the “Nope.” in the text.

The author probably meant “(instance? FictionalCharacter watson-2) ; Nope.”.

Categories: