Errata

Clojure Programming

Errata for Clojure Programming

Submit your own errata for this product.

The errata list is a list of errors and their corrections that were found after the product was released. If the error was corrected in a later version or reprint the date of the correction will be displayed in the column titled "Date Corrected".

The following errata were submitted by our customers and approved as valid errors by the author or editor.

Color key: Serious technical mistake Minor technical mistake Language or formatting error Typo Question Note Update

Version Location Description Submitted By Date submitted Date corrected
ch15?
2nd Paragraph after "Getting Setup with CouchDB and Clutch"

Clutch project's URL has changed.

https://github.com/clojure-clutch/clutch

Old URL in current safari version redirects to that.

Note from the Author or Editor:
Correct.

Change

https://github.com/ashafa/clutch

to

https://github.com/clojure-clutch/clutch

Mike Fletcher  Sep 10, 2012  May 14, 2014
Printed
Page 26
4th paragraph

defprotocol spans a line break (without a hyphen) so that it appears as defproto <nl> col. Ideally it would be clearer that this is all one word.

Note from the Author or Editor:
Remove line break or add hyphenation in "proto col"

Anonymous  May 04, 2012  May 14, 2014
PDF
Page 37
Mutually recursive functions with letfn

Executing the code in a REPL works if not modified.
(letfn [(odd? [n]
(even? (dec n)))
(even? [n]
(or (zero? n)
(odd? (dec n))))]
(odd? 2))
(odd? 11))
;= true

If you change the last line to execute something false, it produces a StackOverflowError.
(odd? 2)
(odd? 0)
(even? 1)
All produce the StackOverflowError.

I was analyzing the code to see if I could figure out how it works when it reaches a false condition. I couldn't. So I decided to attempt to execute it to learn. It failed.

Thanks.

Note from the Author or Editor:
Good catch, sorry for the error!

Change on page 37, replace this code listing:

(letfn [(odd? [n]
(even? (dec n)))
(even? [n]
(or (zero? n)
(odd? (dec n))))]
(odd? 11))
;= true

with this one:

(letfn [(odd? [n]
(if (zero? n)
false
(even? (dec n))))
(even? [n]
(or (zero? n)
(odd? (dec n))))]
(odd? 11))
;= true

Jimmie Houchin  Jul 02, 2012  May 14, 2014
Printed
Page 37-38
bottom of 37, top of 38

Both definitions of strange-adder have an extra (extraneous) right paren on the end.

Note from the Author or Editor:
Only the *second* `strange-adder` definition has an extraneous right paren, top of page 38.

Kenneth Beesley  Apr 03, 2014  May 14, 2014
Printed, ePub
Page 42
pitfall padagraph near the end of the page

Equivalent expression for condition checking in if special form is wrong. It doesn't work for bolean false (it evaluates to true).

Should be (and (not (nil? x)) (not (false? x)))

Note from the Author or Editor:
PDF page 42, last line, change

... which is equivalent to (or (not (nil? x)) (true? x)) ...

to :

... which is equivalent to (and (not (nil? x)) (not (false? x))) ...

Marko Mitrovic  Jan 01, 2013  May 14, 2014
PDF
Page 56
end of repl interaction

(= five (StatefulInteger. 42))
;= true

should read:

(= six (StatefulInteger. 42))
;= true

my full interaction:

$ javac StatefulInteger.java
$ mv StatefulInteger.class ../classes/
user> (import 'StatefulInteger)
StatefulInteger
user> (def five (StatefulInteger. 5))
#'user/five
user> (def six (StatefulInteger. 6))
#'user/six
user> (.intValue five)
5
user> (= five six)
false
user> (.setInt five 6)
nil
user> (= five six)
true
user> (defn print-number
[n]
(println (.intValue n))
(.setInt n 42))
#'user/print-number
user> (print-number six)
6
nil
user> (= five six)
false
user> (= five (StatefulInteger. 42))
false
user> (= six (StatefulInteger. 42))
true

Note from the Author or Editor:
Thanks for catching that!

Change on page 56:

`(= five (StatefulInteger. 42))`

to

`(= six (StatefulInteger. 42))`

lina mist  May 15, 2012  May 14, 2014
Printed
Page 63
1st paragraph

(reduce max [0 -3 10 48])
;= 10

should be

(reduce max [0 -3 10 48])
;= 48

Anonymous  May 23, 2012  May 14, 2014
PDF
Page 77
footnote 35

35. It is a common for the names of functions that...

should read something like:


35. It is a common practice for the names of functions that...

or maybe simply:

35. It is common for the names of functions that...

Note from the Author or Editor:
Page 77, footnote 35, change

35. It is a common ...

to

35. It is common ...

lina mist  May 19, 2012  May 14, 2014
Printed
Page 108
bottom

Great book! Thanks for writing it.

On my machine:

((comparator compare-magnitude) 10 10000)
;= -1
((comparator compare-magnitude) 100 10)
;= -1
((comparator compare-magnitude) 10 75)
;= -1

not what is in the book.

AFAICS compare-magnitude is not much of a predicate - it is never logically false - no?

Thanks again.


Note from the Author or Editor:
PDF page 108, change this function:

(defn compare-magnitude
[a b]
(- (magnitude a) (magnitude b)))

to:

(defn compare-magnitude
[a b]
(neg? (- (magnitude a) (magnitude b))))

Anonymous  Feb 01, 2013  May 14, 2014
Printed
Page 109
United States

The syntax for *1 has not been previously introduced. I presume that it refers to the result of the last operation.

Note from the Author or Editor:
A footnote pointing towards the full explanation of *1 et al. is misplaced.

Change:

Move footnote '4' from page 305 to page 109, with the referring superscripted numeral appended to callout #2 on page 109:

"*1 holds the value of the last expression evaluated in the REPL. See REPL-bound vars on page 399 for details."

Alan Thompson  Mar 15, 2013  May 14, 2014
PDF
Page 132
Warning note, 1st paragraph

"Remember that only vectors and unsorted maps and vectors have..." should be "unsorted maps and sets have..." - author made a typo substituting sets to vectors.

Note from the Author or Editor:
PDF page 132, change

Remember that only vectors and unsorted maps and vectors have...

to

Remember that only vectors and unsorted maps and sets have...

Artem Oboturov  Jun 17, 2012  May 14, 2014
Printed
Page 145
.

swapped the order of parameter of type set:

you call :

(neighbours %) #{2 3} #{3 } )

but the set are swapped : the correct order of set are , maybe

(neighbours %) #{3 } #{2 3} )

Note from the Author or Editor:
Good catch, Thanks!

Change on page 145:

#{2 3} #{3}

to:

#{3} #{2 3}

Anonymous  Jan 16, 2013  May 14, 2014
PDF
Page 149
Last complete function definition on page

The definition of hex-grid is missing two closing parentheses. The last line should be:
:when w] #{v w}))))

Note from the Author or Editor:
Bizarre?thanks for catching that print error!

Change:

Add two closing parentheses to the end of the `hex-grid` function.

James Elliott
James Elliott
 
May 30, 2012  May 14, 2014
PDF
Page 150
Top of page

The definition of hex-outer-walls is missing two closing parentheses. The last line should be:
:when (not (vertices w))] #{v (vec w)}))))

Note from the Author or Editor:
Bizarre?thanks for catching that print error.

Change:

Add two closing parentheses to the end of the `hex-outer-walls` function.

James Elliott
James Elliott
 
May 30, 2012  May 14, 2014
PDF, Other Digital Version
Page 190
(defn character

(ref (dissoc cdata :validators)
should be:
(ref (dissoc cdata :validator)

The latter working snippet in on github:
https://github.com/clojurebook/ClojureProgramming/blob/master/ch04-concurrency-game/src/com/clojurebook/concurrency/game_validators.clj

Note from the Author or Editor:
s/:validators/:validator/g

Thanks!

Anonymous  Apr 30, 2012  May 14, 2014
PDF
Page 190
enforce-max-health function

The function enforce-max-health only accepts one parameter, but in the character function 2 values are being passed to it, so you get an arity error if you try to use the code as written.

The easiest fix is to change the parameters in enforce-max-health from [{:keys [name health]}] to just [name health].

Also, it isn't clear in that function that the health being passed to it is the max-health value when the function is being created as a validator, it just happens to be that max-health is set to the health value at the same time. It does state in point 1 that it returns a function that acceps a char's "potential" new state, but still, It might be clearer to declare the variable in enforce-max-health as "max-health" instead of health.

Note from the Author or Editor:
Yup, we caught this as well when preparing the sample code repository (i.e. https://github.com/clojurebook/ClojureProgramming/blob/0913e2edc38b38f2da80d41aa2b28d3861a69947/ch04-concurrency-game/src/com/clojurebook/concurrency/game_validators.clj#L29).

Change on page 190:

[{:keys [name health]}]

[name health]

You're right that the parameter should probably be called `max-health`?we'll see about that in the second edition, etc. Thanks!

Mark Fisher  Feb 03, 2013  May 14, 2014
PDF
Page 197
Figure 4-3

On page 197, the figure 4-3 displays two 'ref b' timeline. The bottom timeline should be 'ref a'. Figure 4-4 displays this correctly.

Note from the Author or Editor:
Update figure 4-3. Change bottom "ref b" to "ref a".

Francois Nguyen  May 15, 2012  May 14, 2014
PDF
Page 199
2nd line

"deferencing" should be "dereferencing"

Note from the Author or Editor:
s/deferencing/dereferencing

Gianluca Torta  Apr 16, 2014  May 14, 2014
PDF
Page 218
1st code listing

This code listing begins:

(require '[net.cgrand.enlive-html :as enlive])
(use '[clojure.string :only (lower-case)])
(import '(java.net URL MalformedURLException))

but needs to also include:

(use '[clojure.java.io :only (as-url)])

and

(import '(java.util.concurrent BlockingQueue LinkedBlockingQueue))

or typing in the following code won't work.

Note from the Author or Editor:
Good catch! We found this before publishing the sample code repository (https://github.com/clojurebook/ClojureProgramming/blob/master/ch04-concurrency-webcrawler/src/com/clojurebook/concurrency/webcrawler.clj), but the book will change shortly as well.

Changes:

On page 219, in the code listing that starts with `(def url-queue (LinkedBlockingQueue.))`, *prepend* this line:

(import '(java.util.concurrent BlockingQueue LinkedBlockingQueue))

On page 220, in the code listing that starts with `(declare run process handle-results)`, *prepend* this line:

(use '[clojure.java.io :only (as-url)])

jcDelta  Jul 26, 2012  May 14, 2014
PDF
Page 240
1st code listing

the first code listing:

(defmacro while
[test & body]
(list 'loop []
(concat (list 'when test) body)
'(recur)))

should be (or similar):

(defmacro while
[test & body]
(list 'loop []
(concat (list 'when test) body
'((recur)))))

so that "recur" is produced as part of the final "when" form.

Note from the Author or Editor:
Good catch, thanks!

Change on page 240, replace this code listing:

(defmacro while
[test & body]
(list 'loop []
(concat (list 'when test) body)
'(recur)))

with this one:

(defmacro while
[test & body]
(list 'loop []
(concat (list 'when test) body
'((recur)))))

Petr Novotnik  Jun 15, 2012  May 14, 2014
PDF
Page 263
Second paragraph, last sentence

You have ?Thankfully the term is depreciative enough?? and I think you meant deprecatory or perhaps deprecative?

Note from the Author or Editor:
PDF page 263, change

Thankfully, the term is depreciative enough

to

Thankfully, the term is disparaging enough

James Elliott
James Elliott
 
Jun 05, 2012  May 14, 2014
PDF
Page 281
Several evaluated expression at the beginning of the page

(def felix (schr?dinger-cat))
;= #'user/felix
@felix
;= :dead
(schr?dinger-cat)
;= #<Schr?dingerCat@3248bc64: :dead>
(schr?dinger-cat)
;= #<Schr?dingerCat@3248bc64: :alive>

Function schr?dinger-cat creates an instance of cat. So it must be different objects. As we can see two succesive calls of function returns one object.

Note from the Author or Editor:
Whoops, copy/paste error. :-)

Change:

Replace the second occurrence of "3248bc64" with (e.g.) "b28eed01".

Yury  Aug 27, 2012  May 14, 2014
PDF, Other Digital Version
Page 285
lat line

The last line lacks a '}', that is:
:dims (fn [pt] [2 1]))
should be:
:dims (fn [pt] [2 1])})

Wrong also on: https://github.com/clojurebook/ClojureProgramming/blob/7521bcfb52cdf7e598bca3c4e7860d795a67992c/ch06-datatypes-repl-interactions.clj

Note from the Author or Editor:
Page 285, last line, add the missing curly brace. Change:

:dims (fn [pt] [2 1]))

to:

:dims (fn [pt] [2 1])})

Roberto Mannai  May 04, 2012  May 14, 2014
PDF, Other Digital Version
Page 356
5th element on the list

"read-only portions of the appropriate java.io.*" should be "read-only portions of the appropriate java.util.*"

Note from the Author or Editor:
Page 356, 5th bullet point, change

read-only portions of the appropriate java.io.*

to

read-only portions of the appropriate java.util.*

Roberto Mannai  May 09, 2012  May 14, 2014
ePub
Page 372
Example 9-15 step 3

The text is bizarrely formatted, with "?proxy requires two vectors as its first two arguments:? superimposed over later text. Issue is visible in iBooks and in Readium.

Note from the Author or Editor:
Looks fine in PDF; O'Reilly staff will need to verify/fix for ePub, as I don't have an ePub reader handy.

empiricalthought  Feb 14, 2013  May 14, 2014
PDF
Page 380
the last line in the code example (excluding comment lines)

On the line
(println "Error!" (.getMessage) @e)))

the .getMessage method is missing the parameter. Should be:
(println "Error!" (.getMessage e) @e)))

Note from the Author or Editor:
In the code listing on page 380, change:

(println "Error!" (.getMessage) @e)))

to

(println "Error!" (.getMessage e) @e)))

Anonymous  Nov 11, 2013  May 14, 2014
PDF
Page 387
4th paragraph

The note says "Here, we deref the value of the sample-values var", but in the code (both Java and Clojure) the var is named 'keywords'.

Note from the Author or Editor:
Change "sample-values" to "keywords" in callout 4 on page 387.

Anonymous  Nov 12, 2013  May 14, 2014
Printed
Page 439
2nd paragraph

Getting the declared methods for the round function uses (round foo), but should be (class round).

So this:

(seq (.getDeclaredMethods (round foo)))

should be:

(seq (.getDeclaredMethods (class round)))

Note from the Author or Editor:
Thank you for the report!

Change:

s/round foo/class round/g

Ulrik Sandberg  Sep 02, 2012  May 14, 2014
PDF
Page 439
United States

the return value in
(defn idem ^long [^long x] x)
;= #'user/long

should be #'user/idem

Note from the Author or Editor:
PDF page 439, change

(defn idem ^long [^long x] x)
;= #'user/long

to

(defn idem ^long [^long x] x)
;= #'user/idem

art gittleman  Nov 05, 2012  May 14, 2014
PDF, Other Digital Version
Page 460
last paragraph

The factory function:
(defrecord Chihuahua [weight price]

should not get input parameters:
(defrecord Chihuahua []

otherwise the following code in the text will not work:
(main (Chihuahua.))

(Check also: https://github.com/clojurebook/ClojureProgramming/blob/master/ch12-patterns-repl-interactions.clj#L83)

Note from the Author or Editor:
PDF page 460, change

(defrecord Chihuahua [weight price]

to

(defrecord Chihuahua []

Roberto Mannai  May 14, 2012  May 14, 2014
PDF, Other Digital Version
Page 466
"require" instruction

Should be "use", not "require":

(use '[ring.middleware cookies session])

(def my-app (-> my-app
wrap-cookies
wrap-session
wrap-logger))

Note from the Author or Editor:
Good catch, thanks!

Change on page 466:

Replace

wrap-cookies

with

ring.middleware.cookies/wrap-cookies

and replace

wrap-session

with

ring.middleware.session/wrap-session

Roberto Mannai  May 15, 2012  May 14, 2014
PDF
Page 486
attr function definition

The argument for attrs function should be attr-map instead of attrs. Accordingly, the line
(->> attrs
should be replaced with
(->> attr-map

Note from the Author or Editor:
In the code listing on page 486 (in the middle of the page), change:

[attrs] to [attr-map]

AND

->> attrs

to

->> attr-map

Anonymous  Nov 16, 2013  May 14, 2014
PDF
Page 492
United States

The keys passed as properties to DriverManager.getConnection are :username and :password. According to the jdbc spec they should include :user and :password
It may be that :username works with mysql but it doesn't work with db2

Note from the Author or Editor:
PDF page 492, change two occurrences of:

:username "login"

both to:

:user "login"

Vincent Thomas  May 31, 2012  May 14, 2014
PDF
Page 541
Code callout 2 (and 1)

Code reads:
((PUT ["/:id" :id #"\d+"]
[id url]
(list "You requested that " url " be assigned id " id))
{:uri "/590" :params {:url "http://clojurebook.com"} :request-method :put})
;= {:status 200, :headers {"Content-Type" "text/html"},
;= :body "You requested that http://clojurebook.com be assigned id 590"}

You don't get the result in the last line from the function
(list "You requested that " url " be assigned id " id))

You can get it from
(str "You requested that " url " be assigned id " id))

Note from the Author or Editor:
In the code listing in the middle of page 541, change:

(list

to

(str

Peter West  Jan 02, 2014  May 14, 2014
PDF
Page 564
Example 17-4

The plugin slot of defproject:
plugins [[lein-ring "0.6.2"]]
is missin the colon. Should be:
:plugins [[lein-ring "0.6.2"]]

Note from the Author or Editor:
In Example 17-4, change:

plugins

to

:plugins

Anonymous  Nov 18, 2013  May 14, 2014
PDF
Page 586
First paragraph/code block

In the third example expression (first complete one on this page):

(run* [x]
(fresh [_]
(conso _ 3 [1 2 3])))
;= ((2 3))

the first 3 should be replaced with an x to get the desired output:

(run* [x]
(fresh [_]
(conso _ x [1 2 3])))
;= ((2 3))

Note from the Author or Editor:
Good catch!

Change on page 586:

(run* [x]
(fresh [_]
(conso _ 3 [1 2 3])))

to

(run* [x]
(fresh [_]
(conso _ x [1 2 3])))

aminggs  Apr 17, 2012  May 14, 2014