
First chapter of Kernighan and Donovan's new Go book [pdf] - rexignis
http://www.gopl.io/ch1.pdf
======
realrocker
From the book:

"But it has comparatively few features and is unlikely to add more. For
instance, it has no implicit numeric conversions, no constructors or
destructors, no operator overloading, no default parameter values, no
inheritance, no generics, no exceptions, no macros, no function annotations,
and no thread-local storage."

~~~
yokohummer7
> no default parameter values

Hearing this leaves a bad taste in my mouth, because one of the (mis)features
I've found in Go is its implicit default value in struct initialization. In
Go, you don't get a compile error when you miss some fields while initializing
a struct. e.g.

    
    
      type T struct {
        a int
        b string
        c float64
      }
      
      t := T{c: 1.5}
    

will happily set `t.a` to 0 and `t.b` to an empty string. While this is useful
for maintaining backward compatibility (adding more fields to a struct doesn't
break upstream code), it also hinders discovering genuine mistakes at compile
time. So typical Go programs end up using 0 or an empty string as a sentinel
value. This is probably what made me feel Go's dynamic nature the most. It
really is pretty close to a dynamic language.

~~~
jerf
I should explicitly state I seem to be in the minority in the Go community
here, but: You don't get a compiler error if you initialize by name. You _do_
get a compiler error when you initialize by position. In my minority opinion,
you can and should use that to your advantage whenever possible. Some structs
are clearly "configuration-like", for instance, and you don't want an error if
a new option shows up, which will probably default to whatever you had before
anyhow. Some structs are clearly data structures, and you'd really like to
know if your two-dimensional point suddenly grew a third parameter. Of course
it's not a bright shining line, but it's often pretty easy to tell which you
have, or which thing you want, and use the correct initialization.

In this case, if you used:

    
    
        T{4, "hello", 3.5}}
    

most future type changes to the T struct will become compiler errors. (It
won't be if the types are compatible, for instance, changing the first to a
float would still result in a legal struct. If you have richer types in play
that is less of an issue.)

golint will then complain at you, but you can pass a command-line switch to
turn that off.

(This, amusingly, puts me in the rare position of siding against the Go
community, on the side of the language designers. Bet you may not have known
there is such a position to take. :) )

~~~
edsrzf
One non-obvious downside is that the Go 1 compatibility guarantee doesn't
apply to struct literals that don't use field names. (I suspect you're aware
of this, but other readers might not be.)

So it's possible that a future version of Go could add a field to some struct
you're using and your code will stop compiling when you upgrade. It's an easy
fix, of course, so it's not that big of a deal, but it's worth realizing.

~~~
jerf
The point is that if I'm using stuct literals, I _want_ the compiler to stop
me for those structs.

I'm explicitly rejecting the idea that all struct changes should be possible
without producing compiler errors. Compilers errors when the guarantees your
code is based on changes is a _feature_ , not a bug.

------
Omnipresent
To those in the Go community:

\- What is Go well suited for other than network programming? \- Why might one
decide to write the backend API of their web app in Go, compared to say
Grails, Python etc.

~~~
endymi0n
Other than some quite significant performance gains, I'd say the main upside
for the case of a backend API would be channels. Concurrency is dead simple in
Go - and if you want to do 5 different requests to ElasticSearch in parallel
and merge the results when all of them are finished (like we do for Universal
Search), that's just a few lines of very readable Go. Try that with a GIL,
sure, multithreaded Python and Ruby is possible, but it's not for the faint
hearted and not as easy to read.

Moreover, I love static deploys and cross compilation with Go. Compile your
app (even to Windows!), copy it to a server, simply run it as a single binary.
No dependency management, no apt-get & easy_install & pip, it just runs.

~~~
muraiki
While Go does provide channels, I'd argue that they are not dead simple. I'm
not saying this to bash Go, and I have willingly used it to solve problems.
But I think it needs to be made more clear that this often-praised aspect of
Go may disappoint those who are familiar with alternative techniques available
in mainstream (read: not Haskell) languages.

For instance, look at the "Go Concurrency Patterns: Pipelines and
cancellation" article:
[https://blog.golang.org/pipelines](https://blog.golang.org/pipelines) You'll
notice the line "We introduce a new function, merge, to fan in the results"
and after that, you will see how you have to write merge() yourself for every
different data type that you use. Yes, you will have to repeat this same type
of code, over and over, any time you want to pipeline, fanout, or merge, a new
data type (unless you resort to interface{}). Furthermore, you will have to
use the Go race detector to make sure you didn't actually mess something up.

I can't speak for Python or Ruby, but if you are using Node.js you can use a
library like Bluebird which provides promise combinators. Then it's very easy
to perform 5 requests and to handle errors and cancellation on one or more
requests. You can do this and more on any arbitrary data type without writing
merge() and nesting coroutine returning functions repeatedly.

So for handling async operations like dealing with APIs, I personally prefer
tools like promise combinators or reactive programming (see Reactive
Extensions for Javascript, also available in many other languages, or supplies
in Perl 6 if you're crazy like me) over the significantly more manual approach
of using typed channels in Go. I'm sure there are tasks where tight manual
control of channels is important, but for the type of work I've been doing Go
is simply too low level.

This article goes into more detail on the weaknesses of pipelining in Go:
[https://gist.github.com/kachayev/21e7fe149bc5ae0bd878](https://gist.github.com/kachayev/21e7fe149bc5ae0bd878)

~~~
rudolf0
>This article goes into more detail on the weaknesses of pipelining in Go:
[https://gist.github.com/kachayev/21e7fe149bc5ae0bd878](https://gist.github.com/kachayev/21e7fe149bc5ae0bd878)

This write-up provides some great arguments for why generics could be very
useful for abstracting away some of the details of concurrency management.

I find it odd how so many Go developers insist generics are totally
unnecessary.

~~~
skywhopper
Generics can be nice, but they're clearly not "necessary" to any of the
languages that don't support them. Besides, the cost that generics would exact
in terms of syntax complexity, compile time, and startup time is something
that many Go-detractors dismiss as irrelevant.

Myself, I think enforced tab-based formatting is utterly insane, but
ultimately it doesn't matter. Part of the philosophy behind Go is to keep
certain things very simple, and leaving generics out is a big part of that. I
don't think that they're going to change their mind because non-Go programmers
advocate for them. If that makes it the wrong language for your project, then
there are so many others to consider.

~~~
lobster_johnson
But Go already has generics: channels, maps, make(), len(), etc. are work on
generic types. You couldn't have typed channels without generics!

Go just doesn't have any syntactical way of declaring generic types. But given
the above, nobody can argue that generics isn't extremely useful, even in the
context of Go. "Oh, but the official library is special because it's part of
the language", someone might argue. But one would have to be fairly damn
obtuse to claim that Go would be better without the built-in generics, or that
for some reason those benefits wouldn't extend to the language as a whole, if
implemented.

I'm really surprised the authors of Go decided to allow generics only for the
official library, because they've had to jump through some serious hoops to
avoid it. If you look at "reflect", "builtin" and "sort", to pick a few, those
packages are a graveyard of typing awkwardness. Look at the sorry state of the
sort package, which even has a special function to sort strings. It goes on
and on; every time I work with Go code, I end up implementing functions like
min() and max() and cmp(). Why is "range" special? Why isn't there a way for
generate iterators for any value? Etc.

Go is "simple", sure, but ends up being rather complicated as a result, with
tons of the same code having to be written over and over for different types,
and tons of typecasting between interface{} and real types, and so on. Nobody
(as far as I can see) is asking for Haskell-style typeclasses or operator
overloading or type traits or higher-kinded types or any of that. Several up-
and-coming languages (such as Nim) implement generics without going overboard
with complexity; quite the opposite, generics makes those languages simpler.

~~~
rudolf0
>Go is "simple", sure, but ends up being rather complicated as a result, with
tons of the same code having to be written over and over for different types,
and tons of typecasting between interface{} and real types, and so on. Nobody
(as far as I can see) is asking for Haskell-style typeclasses or operator
overloading or type traits or higher-kinded types or any of that.

Exactly. We're not asking for much here, just the ability to do the most basic
kind of type parameterization.

The only benefit afforded by missing generics is simplicity in the compiler.
It does nothing or worse than nothing when it comes to simplicity in actual Go
code.

------
nimrody
"Typeset by the authors in Minion Pro, Lato, and Consolas, using Go, groff,
ghostscript, and a host of other open-source Unix tools. Figures were created
in Google Drawings."

groff still going strong... although it seems like Kernighan got tired of
drawing using the 'pic' language...

~~~
copperx
Yep, I was really curious to see if he had finally given up and gone to TeX,
Indesign, or the like.

I guess that if one's not dealing with a lot of math, groff is enough for many
typesetting jobs.

I'm curious as to which version of groff they used. Heirloom groff? GNU groff?
hmm...

~~~
eric_the_read
groff == GNU roff by definition. I suspect by "Heirloom groff" you mean troff
or nroff.

------
vezzy-fnord
Interesting to see that the direct lineage from Pike's prior languages and CSP
experiments is reaffirmed. I wrote about this here earlier, with some notable
disagreements in response:
[https://news.ycombinator.com/item?id=9711639](https://news.ycombinator.com/item?id=9711639)

~~~
claystu
Nice to see Oberon getting its fair share of credit too

------
middleclick
Question for the Go experts out there: does it make sense to buy this book to
learn Go or are there better tutorials/books?

~~~
pm90
Effective Go is a great intro:
[https://golang.org/doc/effective_go.html](https://golang.org/doc/effective_go.html)

Also, check out the blog posts for more information on specific topics:
[http://blog.golang.org/](http://blog.golang.org/). They are _really_ well
written.

~~~
andmarios
^ This! It is one of the reasons I like Go. Effective Go is all you need to
understand the language and be able to read even the most complex Go programs.

------
Animats
This is much better than the previous Go documentation, particularly in the
concurrency area. The previous Go documentation introduced goroutines and
channels, stated the mantra "share by communicating, not by sharing", and then
gave examples with variables shared between goroutines.

It now seems to be recognized that, in Go, if you want to lock shared data,
use the lock primitives. Don't try to construct locking primitives from
channels; that's error-prone and hard to read. This new manual seems to
recognize this. When they want a shared counter, they use a shared counter
with traditional locks.

~~~
Jabbles
You've been misinformed. The 2009 version of Effective Go stated, as it does
now:

"This approach can be taken too far. Reference counts may be best done by
putting a mutex around an integer variable, for instance."

[https://web.archive.org/web/20091113154825/http://golang.org...](https://web.archive.org/web/20091113154825/http://golang.org/doc/effective_go.html#sharing)

~~~
nosequel
Of course if you care about speed at all, you will stay away from Go's
mutex's. Time your own code, it is shocking how slow they are. I haven't
published my own test times, but with a quick search here's an example of a
10ms loop taking 2s with mutex's.
[http://www.arkxu.com/post/58998283664/performance-
benchmark-...](http://www.arkxu.com/post/58998283664/performance-benchmark-go-
lang-compares-to-java)

~~~
staticint
A mutex held for up to 10ms on each iteration, over 500 iterations, averaging
out to 2s doesn't seem surprising at all. In fact, this is quite expected. It
would take considerably longer if the random sleep hit 10ms every time.

If you modify the code to release the lock before sleeping...

    
    
        func (c *Counter) add(ch chan int) {
                c.Lock()
                tmp := c.Num
                c.Unlock()
                tmp += 1
                time.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond)
                c.Lock()
                c.Num = tmp
                c.Unlock()
                ch <- 1
        }
    

...and reacquiring it after, it still finishes in 10ms on my machine, as you'd
expect. As you can see, the problem isn't so much that locks are inherently
slow in Go, but rather the mutex, as the acqusition function name implies, is
doing what it is supposed to do: Lock. What is true is that you have to be
careful to use them properly.

------
sinatra
This is a good place to ask this (because Go posts attract a lot of
commenters, even those who dislike Go and like some other language):

Which language/framework would you choose today for writing WebServices?
Preferably with the following characteristics: static type (or at least static
analysis), easy deployment (ex, generates a single binary like in Go),
supports concurrency very well, is small/simple, has good tooling and debug
support, and is fun to write. Go (except for good debug support)? Elixir
(dunno how good it is with deployment and debugging)?

~~~
MCRed
Elixir is what I would choose. I think of deployment as a one time cost. So,
the cost of exrm+docker solves your build problem and then your deployment is
like a "single binary". (except its a single docker container which is
sufficient for me, maybe not for you.)

As I understand it the go runtime must pause to resolve atomic locks for all
the goroutines running. So, when you're doing a dozen goroutines in your app
it's not a problem, but you couldn't do thousands of them. Meanwhile elixir
processes can handle millions of processes without blocking like that, and
that plus the ... strength... of immutable memory (vs. shared in go) makes me
like elixir, _especially_ when concurrency is important. (I don't consider go
to be a concurrent language in this regard.)

Good tooling and debug support: I can't compare the two languages in this
regard, go seems to have good library support. Elixir has excellent tooling
and debug support (REPL mainly, and really nice error messages), and I think
Elixir has good library support too.

Fun to write: So far for me, Elixir wins this hands down. Go is running neck
and neck with Erlang in the "not very fun to write" range for me.

Of course this is all personal opinion.

The only objective thing is- if you need real concurrency and to build a
distributed system (go doesn't even have the concept of language support for
Nodes) then Elixir is the way to go.

If on the other hand you need max compiled speed on a single node, the Go wins
hands down.

~~~
vezzy-fnord
No such thing as Elixir processes. They're Erlang processes because they're
constructs of the EVM. Whether or not you consider the latter fun to write is
irrelevant.

~~~
MCRed
Of course. I don't think anyone is pretending like Elixir isn't built on top
of erlang.

------
srtjstjsj
Link is to Chapter 1 with no context about whole book/availaibility.

Book homepage is here: [http://www.gopl.io/](http://www.gopl.io/)

mods, please fix

Several free full Go eBooks listed at
[http://hackershelf.com/topic/golang/](http://hackershelf.com/topic/golang/)

------
Armand_Grillet
I'm currently reading it as I started to program in Golang only one month ago
and I'd never heard of goimports, this is a nice tool! Mixing it with
GoSublime and it does a really good job [http://michaelwhatcott.com/gosublime-
goimports/](http://michaelwhatcott.com/gosublime-goimports/)

The book is well written and it looks like it covers a lot of common topics, I
think I'm gonna buy it.

------
jasonjei
Just as K&R introduced us to "Hello, World," I'm amused they adapted their
first program to an Unicode world: "Hello, 世界." Seems like a great first
chapter, covering computer graphics and web server/byte fetching to boot.

~~~
vorg
> they adapted their first program to an Unicode world: "Hello, 世界."

Would be nice if you could compose those complicated Unicode characters from
simpler building blocks, e.g.

    
    
        fmt.Printf("Hello, %a", "→↘𠃊廿↓田介")

~~~
jzelinskie
I think that would be a fun way to practice kanji, but I'd much rather just
type "seikai" and press enter. Modern IMEs are awesome.

------
jfb
K&R is a great book. Even though I have no interest in Go, I'll read this,
just to see if it's as good.

------
rmcpherson
I noticed that the lissajous program in 1.4, as included, generates non-random
lissajous figures since the random number generator is not seeded. I couldn't
find any reference to this in the text and this could be confusing to
beginning readers. Is there a recommended way to submit errata?

~~~
LVB
You're correct, but in the interest of:

 _We’ll discuss these topics only briefly here, pushing most details off to
later chapters, since the primary goal right now is to give you an idea of
what Go looks like..._

it's probably clearer to use the default random source.

~~~
rmcpherson
Good point, but I also think it will be confusing to beginners who compile and
run the program only to find that it always generates the same figure without
any explanation as to why. Both the package documentation and text say that
the generated figures will be random.

The fix is just a couple lines and, I would argue, should be included in the
source to eliminate the surprising behavior.
[http://play.golang.org/p/1WlhOdJ1pk](http://play.golang.org/p/1WlhOdJ1pk)

------
fsloth
Would Go provide a viable alternative to C++ for numeric and computer graphics
'kind of stuff'? I have no problem with C++ but the better-than-python
proclamations got me intrigued.

~~~
vvanders
Given that there's a GC and from what I understand(I'm no go expert) limited
ways to specify memory layout I'd say no.

~~~
fmstephe
I am curious about the limitations around memory layout. Go provides a fair
amount of control to the programmer. Fields appear in the order declared in a
struct (although potentially padded), structs declared as values, not
pointers, are located in memory with the declaring struct and we can have
arrays and slices of non-pointer structs they will all be arranged
contiguously in memory.

I am not a C/C++ programmer are there more powerful facilities provided in
these languages?

Real question, not trying to start a flame war :)

------
gjvc
This is going to be the standard text for the language. The quality of writing
is exceptionally good. It's high time the AW professional computing series had
another hit.

------
Artemis2
The K&R for Go, sounds great!

~~~
gauravm
Sadly, there is no 'R' anymore :-/

~~~
rm445
It's a little odd, given that Kernighan and Pike have written a couple of
excellent programming books together, and with Rob Pike's leadership in the Go
project, that this one isn't K&P.

------
pkrumins
I just pre-ordered this book. I already have a feeling it will make into my
favorite book series [1].

[1]: [http://www.catonmat.net/blog/top-100-books-part-
one/](http://www.catonmat.net/blog/top-100-books-part-one/)

------
tyrel
One of my co-workers preordered this, I hope to skim through it if he brings
it into the office.

------
linuxfan
Can people post their opinions on static linking of go binaries? Doesn't it
result in increased size of runtime binaries when compared to those generated
by C/C++?

~~~
kid0m4n
Yep. It does; but then again my entire static binary (no dependency on libc
even) is around 10 MB in size...

I love being able to pull down a docker container that fast!

------
oconnor663
> ...its approach to data abstraction and object-oriented programming is
> unusually flexible.

I'm not sure I can get behind that without generics.

------
rendambathu
Hope this book is going to be another Epic and Great reference like this
gem[1]

[1]
[http://t3.gstatic.com/images?q=tbn:ANd9GcTK3WbaQiO5mCmvRGtvc...](http://t3.gstatic.com/images?q=tbn:ANd9GcTK3WbaQiO5mCmvRGtvcokJUyrd2wcpOj3WcgO8TQyecr3_TrmU)

~~~
_kst_
The link is to an image of the front cover of K&R2 (Kernighan & Ritchie, "The
C Programming Language", 2nd edition). You probably meant the image to show up
in your comment, but it didn't.

------
dataminded
They've proven that they can make a PDF. Will they sell me one?

------
peter303
I still prefer forced data abstraction, i.e. classes as a core construct. GO
does not force that. Data abstraction, when properly done maps the code more
closely into the problem domain to be solved. In the long run that makes the
code more maintainable and extensible.

~~~
why-el
I am really not sure this is true. In my opinion classes force an premature
taxonomy almost all the time. I like that you can simply attach methods to
structs when you decide you want object like behavior.

~~~
tomcam
I understand both points of view but lean strongly toward why-el's. If there's
one thing Java has taught us it's that "premature taxonomy" (love that term)
can be a huge unnecessary tax on small to medium sized projects.

------
ape4
er, they left a couple things out of the family tree (page xii). Like C++,
Java, C#, ...

~~~
DocSavage
It's safe to say that C++ had an influence on the Go language at least as what
_not_ to do. The emphasis on language simplicity and compile speed seemed to
be a result of fairly large C++ code bases at Google.

------
claystu
I have no idea what they will specifically say regarding calling C from Go,
but the table of contents says that part is only going to be about five pages.

I really wish they would beef up this portion of the book.

~~~
harikb
The fact that it is a bit non-intuitive to call C from Go is exactly where
there are so many 'Pure Go' libraries. I consider this as a short-term hurdle
with long-term benefit.

~~~
claystu
It would be nice if all C libraries get rewritten in Go, but realistically,
there are way too many for that to ever happen.

~~~
skybrian
There are lots of libraries in C (and Java) but the question is which ones are
essential for whatever you're trying to do? There are lots of Go programs you
can write just using the standard library. That appeals to me since I'm
generally in favor of avoiding unnecessary dependencies. But if you need it,
you need it.

~~~
TillE
It really depends on what you're doing, but even in common obvious stuff like
networking, there can be functionality in libcurl or OpenSSL that you really
need but isn't replicated in Go. Several years ago I remember trying to do SSL
certificate verification with Python and finding the standard library lacking.

Also bear in mind that good compatibility with C also means good compatibility
with just about every other compiled language, including Rust.

