New 18Jan2016. Updated 6April2016
This page is in group Technology
“The Go Programming Language” by Alan A. A. Donovan & Brian W. Kernighan. Addison-Wesley. ISBN-13: 978-0134190440, ISBN-10: 0134190440. I am commenting on the first paper printing of October 2015, © 2016 by the authors. The book’s web page is at http://www.gopl.io/
Following the K&R book and the C language version abbreviation K&R it’s probably natural to call this book D&K.
The errata is at http://www.gopl.io/errata.html. My comments below should not be in that list.
This is an excellent book that makes me think. I learn a lot from it. Disclaimer: my interest here is the concurrency and channel chapters
– 8.4.4. Buffered channels
Page 232 (figures)
The problem with these figures in the Go context is that they show the channel’s pointer that points to a queue with an arrow. In that case it points to the first element, and sending the "A" first shows the "A" in the leftmost  position. This is the normal data struct view.
However, my view is that logically it’s better to think of the buffered channel as a pipe and the arrow as data flow. (In this case we need to remove the inside dot in ch and start the line from the outside of the box making a standard channel arrow, as they do elsewhere in the book). In that case the figure would have been ch --> "C", "B", "A" with "A" as the rightmost. The figure could then easily be expanded like cleft --> "C", "B", "A" --> cright and easier to understand. In my opinion this view would also easier visualise what’s going on in the channel’s buffer
The choice between unbuffered and buffered channels, and the choice of a buffered channel’s capacity, may both affect the correctness of a program.
Failure to allocate sufficient buffer capacity would cause the program to deadlock
A consequence of the last sentence would be that a zero buffered channel would cause the program to deadlock, since sufficient probably not would include zero capacity. The authors must agree that’s a wrong conclusion, but I am uncertain why they make such a broad statement. In fact zero may be sufficient. Deadlock has to do with a cycle in the dependency graph. It may (or may not) occur with zero channel buffer capacity, with enough capacity or with too little capacity (see note 092).
(I remember once I modelled a pattern in Promela using Spin. No matter how large capacity I had in the channel I ended up with “invalid end-state” (deadlock). The solution wasn’t to increase the capacity but to change a role to break the cycle.)
This is one of the most cited misunderstandings; a variant of the statement that “send and forget” asynchronous programming causes fewer deadlocks. It might. And it might not. But it’s not the pattern I would use in an airplane. A proper analysis is best; the conclusion may be either way.
Find the quote in D&K and fill in the dots, some of which is “..when we know the upper bound on the number of values to be sent on a channel..”. There’s something about establishing the max load through the channel, which is rather ok. Then apply some formal stuff and you might be able to prove that it will never deadlock. But knowing the upper bound of values to be sent is not enough, there is a reader (or readers), and once you start with this there is time. Messages per second in and out. Instead of putting all the undecidedness in the channel it’s much easier to do it inside a process/goroutine and handle a buffer there. It’s even flush’able, and you can prioritize messages and overtake some others. See my XCHAN paper that describes much of this more formally (for CPA-2012 here). As Rob Pike said, we don’t really need buffered channels (note 072). Occam did without; the recipe there was to pipeline processes into a composite “buffer channel process” or make a composite “overflow buffer” process if that was what we wanted. The last change we did in a product was to remove an overflow buffer, not to add one. But of course, a dimension on the channel capacity in a CSP language is nice to have and was missed some times in occam. D&K of course also shows examples of nice usage of them.
– 8.7. Multiplexing with select
Let’s make our launch program print the countdown. The statement below causes each iteration of the loop to wait up to 1 second for an abort, but no longer.
This is only correct if zero waiting is less than one second. It is, but the statement is still meaningless: even to consider the timing of the acceptance of the abort choice in the select statement. The tick input does nothing and this takes logically “zero” time including the for loop. The abort input is taken “immediately” since there is nothing stopping it.
If the goroutine that sends the abort signal would have polled the abort key once every second (which it doesn’t) then this statement would have been more acceptable. But not in the WYSIWYG semantics view of channels: considering the internal of a goroutine out of scope is not what one should normally do (see note 079). In that case the abort signal should be said to be ready immediately when it’s sent.