The Author Online Book Forums are Moving

The Author Online Book Forums will soon redirect to Manning's liveBook and liveVideo. All book forum content will migrate to liveBook's discussion forum and all video forum content will migrate to liveVideo. Log in to liveBook or liveVideo with your Manning credentials to join the discussion!

Thank you for your engagement in the AoF over the years! We look forward to offering you a more enhanced forum experience.

You show data models in Fig 2.5 and 2.6 and it turns out that these are (C.J Date's) 6th normal form of the relational model. It is the (one of the) recommended way(s) to store temporal data in the relational model. See also Temporal SQL and SQL 2011 enhancements for Temporal Data.
[Developing Time-Oriented Database Applications in SQL: RICHARD T. SNODGRASS]
[Temporal Data and the Relational Model: Date, Darwin and Lorentzos]

Later in this section you talk about "...deleting the bad data..." - what happened to immutable? 1) you are changing the past, and 2) this "delete" may itself be the human error.

Message was edited by:
AlexPeake
Obviously this is just an opinion (and you know what opinions are worth!)

Your examples throughout the book are good in that they exemplify real Clojure code, they are interesting code examples to observe how things are done in Clojure and they often do something quite rich and possibly reusable.

OTOH, they are difficult to follow -- you really have to spend quite some time to understand what they do. And in trying to learn some concept I find that the concept gets lost in the complexity of the example.

What has triggered this comment, because it reminds me of so many previous examples I have struggled through, is section 11.2.1 demonstrating refs. In working through what exactly the chess board program does the whole simple idea of refs is lost. My focus is on trying to figure out what the program does line by line.
WARNING: reset! already refers to: #'clojure.core/reset! in namespace: user, being replaced by: #'user/reset!
In:

5.3.2 Lists as Stacks

You say:

Also, the order of values returned by seq on a list is backwards compared to seq on a vector

What exactly does this mean? (first (seq... returns the same whether list or vector
Since this is now CHAPTER 5 I noted a few issues under the "reply to CHAPTER 5" thread (which now refers to CHAPTER 6)
(now CHAPTER 5)

I cannot follow Listing 5.1 (and I am sure there would be others who cannot)

(defn neighbors
([size yx] (neighbors [[-1 0] [1 0] [0 -1] [0 1]] size yx))
([deltas size yx]
(filter (fn [new-yx]
(every? #(< -1 % size) new-yx))
(map #(vec (map + yx %)) deltas))))


What is happening with neighbors calling neighbors? This does not appear a recursive function? Yet of course the function works.


OK, now I get it - it is a multiple arity function.

It would help greatly to note this.
Minor typos in 5.8 Summary

If our problems are easy solved by collection abstractions

->

If our problems are easily solved by collection abstractions



then it is those abstractions that should be used

->

then those abstractions should be used


Now that we've discussed at each of these types in detail

->

Now that we've discussed each of these types in detail
p. 128

Why, use a PersistentQueue, of course. See section 5 of this chapter for
details.

It is actually 5.4
p. 115

Figure 5.1 A Cons Cell: Each cons cell is a simple pair, a carcar and a
Common Lispcdrcdr. 1. A list with 2 cells, each of which has a value A and B
as the head -- the car in LispLisp terminology, and a list as the tail -- the cdr.
This is very similar to first and rest in Clojure sequences. 2. A cons cell with a simple value for both the head and tail.
This is called a *dotted pair*, but is not
supported by any of Clojure's built in types.


->

Needs editing.

Maybe:

Figure 5.1 A Cons Cell: Each cons cell is a simple pair, a car and a cdr
in Common Lisp terminology. (A) A list with 2 cells, each of which
has a value X and Y as the head -- the car in Lisp , and a list as the tail --
the cdr. This is very similar to first and rest in Clojure sequences.
(B) A cons cell with a simple value for both the head and tail.
This is called a *dotted pair*, but is not
supported by any of Clojure's built in types.
p. 167
Listing 6.3 A Lazy, Tail-recursive Quicksort Implementation

I am guessing that I will not be the only one who does not follow this example?

(defn sort-parts [work]
"Lazy, tail-recursive, incremental quicksort. Works against
and creates partitions based on the pivot, defined as 'work'."
(lazy-seq
(loop [[part & parts :as work] work]
(when work
(if (coll? part)
(let [[pivot & xs] part
smaller? #(< % pivot)]
(recur (cons-when
(filter smaller? xs)
(cons pivot
(cons-when
(remove smaller? xs)
parts)))))
(cons part (sort-parts parts)))))))

(defn qsort [xs]
(sort-parts (list xs)))

The (list xs) is rather subtle and if, as I did, you try and follow sort-parts assuming a list as the argument (and not a list of list) you cannot figure how it would ever work.
Just realized "Being Lazy and Set inYour Ways" is now Chapter 6
p. 120

Clojure can store primitive types inside of vectors using the vector-of function
which takes any of :int, :long, :float, :double, byte, short,
boolean,
or :char

->

Clojure can store primitive types inside of vectors using the vector-of function
which takes any of :int, :long, :float, :double, :byte, :short,
:boolean
, or :char
p. 120

Footnote 37 See section 5.2 on lists for the key differences here.

->

Footnote 37 See section 5.3 on lists for the key differences here.
You give:

(ns chapter14-rabbitmq
(:import (com.rabbitmq.client ConnectionParameters
ConnectionFactory QueueingConsumer)))

(defn new-connection [q-host q-username q-password]
(let [params (doto (ConnectionParameters.)
(.setVirtualHost "/")
(.setUsername q-username)
(.setPassword q-password))]
(.newConnection (ConnectionFactory. params) q-host)))

In the version of RabbitMQ that I just downloaded (2.2.0) there is no "ConnectionParameters" class.

Instead I used:

(ns RabbitMQTest
(:import (com.rabbitmq.client ConnectionFactory QueueingConsumer)))


(defn new-connection [q-host q-username q-password]
(let [conn (.newConnection (ConnectionFactory.))]
(doto conn
(.setVirtualHost "/")
(.setUsername q-username)
(.setPassword q-password)
(.setHost q-host))
conn))

I am no expert so maybe you could check this out.



Secondly, there is an error (I think) in the following:

Now for the var – let’s create one called *rabbitmq-connection* as follows:

(def *rabbit-connection*)



Thirdly you give the example:

(defn send-message [routing-key message-object]
(with-open [channel (.createChannel *rabbit-connection*)]
(.basicPublish channel "" routing-key nil
(.getBytes (str message-object)))))

(send-message "chapter14-test" "chapter 14 test method")

This fails because *rabbit-connection* is unbound - probably because the macro with-rabbit has not been called?

It is hard to follow along with this code.
In:

(defn as-string [date]
(let [y (year-from date)
m (month-from date)
d (day-from date)]
(str-join "-" [y m d])))

You need clojure.string.join not str-join (in 1.2)
In 8.2.4 Mocks vs. stubs you use update-in which is not explained until chapter 13. This makes it difficult to understand the function stub-fn
In the example listing 8.1 you introduce defstruct. This is not explained anywhere in the book. Also from the Clojure docs:

Note: Most uses of StructMaps would now be better served by records.

In 8.2.2 Stubbing, this (missing explanation) is continued with struct-map
I got very confused with the namespaces in this example. Most of what you ran was in the user namespace. Initially I was able to work through the examples in the REPL in the 'chapter08.date-operations-spec namespace. In order to follow the book exactly you need:

1) to create the file chapter08/date_operations_spec.clj
2) early on, and often, to evaluate:

(use 'chapter08.date-operations-spec :reload)

(I use :reload as mentioned in the previous thread so I can re-evaluate and pick up the changes)
Testing chapter08.date-operations-spec

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

You currently have only one assertion (the other two are added in the next page)
After editing date-operations.clj to add the date and day-from functions, you need to :reload

Just re-evaluating:

(ns chapter08.date-operations-spec
(:use chapter08.date-operations)
(:use clojure.test))

fails to define the new functions

So adding a hint in the text will save frustration in figuring out why it does not work.
In chapter twenty-two, we will see many more example of this.

->

In chapter fifteen, we will see many more example of this.
we’ll see examples of this in chapter twenty-two.

->

we’ll see examples of this in chapter fifteen.
In Generating names you say:

In chapter twenty-two, we will see why we actually might want the effect of variable capture when we explore anamorphic macros.

Should be:

In chapter fifteen, we will see why we actually might want the effect of variable capture when we explore anaphoric macros.
I cannot follow what you are saying in:

This situation is illustrated here, where daily-report is an imagined function that ran a report for a day –

(let [now "2009-10-22"]
(shadow-time (daily-report now))

This wouldn’t work as expected, since the value of now that the daily-report function sees would not be "2009-10-22", but a number like 1259828075387. This is because the value set up in the let form above gets captured by the one in the let form generated by the macro.


Where does "...would not be "2009-10-22", but a number like 1259828075387..." happen?
Thanks for the explanation. The confusion is coming from shadow-time. What does it do? Perhaps the defnition of it would help.
You say:

Typically, this function is called from a different thread, so it is a great way to communicate between threads.

An example would be very helpful
Sorry but there are so many minor typos that I cannot spend anymore time pointing them out.

Let's just assume that there are many many more in the book and I leave it to the editors.
How let’s attempt to use a var without a root-binding

->

Now let’s attempt to use a var without a root-binding
It the operation succeeds, it returns true

->

If the operation succeeds, it returns true


but none for coordination with any other state

->

but not for coordination with any other state
changes to one atom is

->

changes to one atom are

or

a change to one atom is



In our case above, we could use pass swap!

->

In our case above, we could pass swap!
(dosync
(send agent-one log-message args-one)
(send-off agent-two send-message-on-queue args-two)
(alter a-ref ref-function)
(some-pure-function args-three))

Clojure’s STM transaction hold all actions that need to be sent to agents until they succeed. In the pseudo-code above, write-to-database and send-message-on-queue are actions that will only be sent when the transaction succeeds. This ensures that even if the transaction is tried multiple times, the side effect causing actions only get sent once.


...sent to agents until the transaction succeeds...


In the pseudo-code above, write-to-database

You should either change the text to log-message or else change the pseudo code to write-to-database
If the validator function return false

->

If the validator function returns false
You state:

We’ll learn about metadata in chapter six.


We are in chapter 6 and I do not see metadata covered much in the book at all

Note also in chapter 2 you state:

"(we’ll learn about meta-data in chapter eight)."
I believe that you should note that await-for returns nil on timeout - this is how you know!
We’ll now send it an action that will cause an exception to be throw, leaving

->

We’ll now send it an action that will cause an exception to be thrown, leaving



This is cause a classic divide-by-zero error

->

This causes a classic divide-by-zero error


If we now to dereference bad-agent

->

If we now dereference the bad-agent
we could cause the current thread to block until they all actions sent to them from the current thread (or another agent) by calling await as follows –

->

we could cause the current thread to block until all actions sent to them from the current thread (or another agent) completed by calling await as follows –
In an MVCC system each contended (threads in the case of Clojure)

->

In an MVCC system each contender (threads in the case of Clojure)
When it runs, the first parameter it is supplied is be the current value of the agent

->

When it runs, the first parameter it is supplied is the current value of the agent
(deref total-cpu-time)
0

Clojure also supports the @ reader macro to dereference agents, so the following is equivalent to calling deref –

@deref ;; should be @total-cpu-time
0
In the code snipped above,

->

In the code snippet above,


which takes a map, a key and an object as parameters

->

which takes a map, a key and a value as parameters


returns a new map with that object associated

->

returns a new map with that value associated
On p. 140 (Requirements for immutability) you say:

The problem with this is that copying something over in this manner is extremely inefficient. Often, the speed of such a copy operation grows linearly with the size of the objects being copied. If every write involved such an expensive operation, it would be impossibly to use in a production environment.

This is problematic because Clojure does use copying so you have set up for a certain friction. (Just look at the example of adding nodes to a tree. You need to copy the root nodes and all nodes down to the added node.)

Better to emphasize the concept of "naive copying" being the problem, or "full copying" being the problem, and then introduce the Clojure approach of reuse of major parts of the structure.

Message was edited by:
AlexPeake
the language runtime has a chance doing something to help supervise writes

->

the language runtime has a chance of doing something to help supervise writes
Programming Clojure partially using the idea of running examples, for example building Lancet. Personally I find following these long examples difficult when learning a new language. I prefer the approach here with small examples illustrating the point in question. I can later build on these small examples to achieve my task. It also makes it easier to go back and reference "how to".

The idea of reading "good code" in the context of a real program is a really good next step after learning the language. Joy of Clojure looks more like this, but I must admit I find that book hard to understand. More study required!
A dirty read happens when a threads reads data

->

A dirty read happens when a thread reads data
it is sometimes worth start with a fresh slate.

->

it is sometimes worth starting with a fresh slate.
I, for one, do not understand:

:constructors {[String] [String]
[String String] [String String]}

Table 5.1 has an explanation, but I do not understand.

Or:

(defn -initialize
([s1]
(println "Init value:" s1)
[[s1 "default"] (ref s1)])
([s1 s2]

Similarly Table 5.1 has an explanation that I do not understand.

You talk about vectors and maps in bot of the above, but not what they mean.

Also, where do the state elements get stored? There is the element:

:state localState

Does this declare some element called "localState"? What is its type?
(println "Init values:" s1 "," s2)
[[s1 s2] (ref s2)]))
prefixed with a dash (-) is because that so they can be identified via convention

->

prefixed with a dash (-) is so that they can be identified via convention
calculator_init.class

->

calculators_init.class
Just an opinion, but it feels like "5.1.6 implementing interfaces, extending classes" needs a simpler and clearer example. Perhaps show a simple interface that you create (in java) and then show the example of implementing?
There’s also array specific versions of the previously seen map and reduce

->

There are also array specific versions of the previously seen map and reduce
One common pattern is a string of methods that need to be called on the same object, or a sequence of methods that need to be chained together, each operating on the result of the previous.

->

One common pattern is a string of methods that need to be called on the same object. Another is a sequence of methods that need to be chained together, each operating on the result of the previous.
when using the dot operator is used in this way,

->

when using the dot operator in this way,
The first form, that uses the parenthesis to enclose the name...

->

The second form, that uses the parenthesis to enclose the name...
Figure 4.1 There are several types of polymorphism. Subtype polymorphism (a form of inclusion) is the most common (think Java/C++) kind of polymorphism but is just is just one kind of several.

->

Figure 4.1 There are several types of polymorphism. Subtype polymorphism (a form of inclusion) is the most common (think Java/C++) kind of polymorphism but is just one kind of several.
(def third-user {:first-name "lambda"
:last-name "curry"
:salary 95000})

(describe-person third-user)

This causes the following to be echoed on the console –

Info about lambda curry is: {:first-name amit, :last-name rathore, :salary 145000}
Bonus is: 5 percent

Should be:

Info about lambda curry is: {:first-name lambda, :last-name curry, :salary 145000}
This implementation of print-amounts is smaller and clearer

(than what? -- there is nothing to compare it with)

(I know - nit-picky - we could read the following text and construct)
3.4.1 {HYPERLINK "omnifocus:///task/oaf2PFq9kN2"}

{HYPERLINK "OMNIFOCUS:///TASK/INZFFHBYEHW"} VECTORS
Let’s finally look at a way of using Java libraries in Clojure code.

-> this is followed by nothing that relates.
prints the log-statement to the console, and the calls the original function

->

prints the log-statement to the console, and the calls then original function

As we mentioned in chapter one, Clojure as language level semantics for safe concurrency

->

As we mentioned in chapter one, Clojure has language level semantics for safe concurrency
You have:

(def expense {‘name “Snow Leopard”
‘cost 29.95})

where the single quote looks like a back-quote

Also, if you copy-paste from the pdf as code samples, the double-quotes are not helpful.
We have already seen anonymous functions before, even if we didn’t call it out them.

->

We have already seen anonymous functions before, even if we didn’t call them out.
This is not really "function composition". Function composition (comp) would be more like:

(map (comp #(.toUpperCase %) #(subs % 1 3)) ["abcde" "fghij" "klmno"])
You should state that the first run of fast-calc takes as long as the slow-calc. Only subsequent runs are fast.
problems of reasonable complexity.complexity.


dividing it up into logical modulesar.
My point was only that this section was titled "Lists", not sequences etc., so the example should be of Lists.
The conj function can be used to add values to a list.
user=> (conj [1 2 3 4 5] 6)

This is a Vector, not a List.

Perhaps:

(cons 0 '(1 2 3 4 5))

or:

(conj '(1 2 3 4 5) 0)
(defn non-zero-expenses [expenses]
(filter zero? expenses))

should be:

(defn non-zero-expenses [expenses]
(filter (comp not zero?) expenses))
We could use the looking construct -> We could use the looping construct
(Not so) humble opinion - Table 6.2 is not helpful because the terms are not defined [shared changes | coordinated changes | independent changes | isolated changes ] -- better to say a little more, like about coordinating a set of changes like updating several items vs. a set of independent changes where there is no coordination, etc. It all makes sense once you have read the chapter, but this leaves you puzzled.


@deref
under 6.5 Agents should be
@total-cpu-time


6.10.2 promises
(def value (deref promise)) should be (def value (deref p)) perhaps?

This section does not explain how to use promises - an example would help.

(Maybe the :communicate between threads example?)