HN Books @HNBooksMonth

The best books of Hacker News.

Hacker News Comments on
Go Programming Language, The (Addison-Wesley Professional Computing Series)

Alan Donovan, Brian Kernighan · 413 HN points · 5 HN comments
HN Books has aggregated all Hacker News stories and comments that mention "Go Programming Language, The (Addison-Wesley Professional Computing Series)" by Alan Donovan, Brian Kernighan.
View on Amazon [↗]
HN Books may receive an affiliate commission when you make purchases on sites after clicking through links on this page.
Amazon Summary
The Go Programming Language is the authoritative resource for any programmer who wants to learn Go. It shows how to write clear and idiomatic Go to solve real-world problems. The book does not assume prior knowledge of Go nor experience with any specific language, so you’ll find it accessible whether you’re most comfortable with JavaScript, Ruby, Python, Java, or C++. The first chapter is a tutorial on the basic concepts of Go, introduced through programs for file I/O and text processing, simple graphics, and web clients and servers. Early chapters cover the structural elements of Go programs: syntax, control flow, data types, and the organization of a program into packages, files, and functions. The examples illustrate many packages from the standard library and show how to create new ones of your own. Later chapters explain the package mechanism in more detail, and how to build, test, and maintain projects using the go tool. The chapters on methods and interfaces introduce Go’s unconventional approach to object-oriented programming, in which methods can be declared on any type and interfaces are implicitly satisfied. They explain the key principles of encapsulation, composition, and substitutability using realistic examples. Two chapters on concurrency present in-depth approaches to this increasingly important topic. The first, which covers the basic mechanisms of goroutines and channels, illustrates the style known as communicating sequential processes for which Go is renowned. The second covers more traditional aspects of concurrency with shared variables. These chapters provide a solid foundation for programmers encountering concurrency for the first time. The final two chapters explore lower-level features of Go. One covers the art of metaprogramming using reflection. The other shows how to use the unsafe package to step outside the type system for special situations, and how to use the cgo tool to create Go bindings for C libraries. The book features hundreds of interesting and practical examples of well-written Go code that cover the whole language, its most important packages, and a wide range of applications. Each chapter has exercises to test your understanding and explore extensions and alternatives. Source code is freely available for download from and may be conveniently fetched, built, and installed using the go get command.
HN Books Rankings
  • Ranked #5 all time · view

Hacker News Stories and Comments

All the comments and stories posted to Hacker News that reference this book.
Actually the influence of the Pascal family and that of the C family are about equally significant, if you go by the chart from the "Go Programming Language" book (available in the free preview, page xiii Most significant is probably the module system, which, in good Turbo Pascal tradition, allows Go to run loops around other C-family languages (looking at you Rust ;) ), and of course the declaration syntax ("i int" instead of "int i").

Since I first came across Go I've been thinking that a Go-based Delphi clone would be really amazing. Maybe someone could breathe some new life into the Lazarus IDE by adding support for Go? Hmmm, actually there already is something: - probably worth keeping an eye on...

I'll structure this in "current/future/recent_past" format if I may.


* The Go Programming Language

* Building Microservices

Plan to do next:

* Designing Data-Intensive Applications

* Designing Distributed Systems

* Unix and Linux System Administration 5th ed, but probably just gonna skip/read chapters of interest, i.e. I wanna get a better understanding of SystemD.

Read last month:

* Learning React

Good for a quick intro but I probably wouldn't read cover-to-cover again, some sections are old, but overall an OK book.

* React Design Patterns and Best Practices

Really liked this one, picked a tonne of new ideas and approaches that are hard to find otherwise for a newbie in JS scene. These two books, some time spent reading up on webpack and lots of github/practice code made me not scared of JS anymore and not feeling the fatigue. I mean, I was one of the people who dismissed everything frontend related, big node_modules, electron, complicated build systems etc. But now I sort of understand why and am on the different side of the fence.

* Flexbox in CSS

Wanted to understand what's the new flexbox layout is about since it's been a while when I've done some serious CSS work. Long story short I made it about half of this and dropped it - not any more useful than MDN docs and actually playing with someone's codepen gave me better understanding in 5 minutes than 3 hours spent with this book.

Designing Data-Intensive Applications is fantastic.
Feb 16, 2017 · clumsysmurf on Go 1.8 Release Notes
I'm wondering if "The Go Programming Language 1e" (Donovan / Kernighan) is still relevant enough to be used as a first book for self teaching.

I personally learned Go about 3.5 years ago myself by following tutorials on, reading the Effective Go document and other blog posts here and there. Then I bought the book last year just out of curiosity. Honestly I find that the experience you gain by reading/writing Go code and consuming online content is more beneficial than the book. The book has some good parts, but I don't think it’s as practical as online resources.
> Honestly I find that the experience you gain by reading/writing Go code and consuming online content is more beneficial than the book.

This applies to almost all languages and technologies!

Yes, but sometimes it is much easier to get moving with a good textbook.

With Go, a few online tutorials and the documentation that comes with Go itself, were all I needed to get going. I am not sure if that was an explicit design goal, but I found the language very easy to learn.

I believe it was an explicit design goal. They wanted new employees joining from straight out of college to be effective within Google's codebase as soon as possible. Therefore the learning curve is pretty low if you already know another mainstream programming language.
The answer is yes. This is the go version 1 compatibility promise [0]. The maintainers have been very careful to not break compatibility, even if it means bug fixes.


Yes, Go maintains strict backwards compatibility, you can apply everything from the book no problem (unless it exploits a go bug which I don't think it does), though you'l miss out on the shiny new stuff.
It is. I already knew Go, but read it from cover to cover. It's a very nice book, and as was said, the Go1 compatibility promise will ensure it stays relevant for a long time.
Yes, read that book cover to cover, it is a really nice book which teaches you concepts, it might not contain the latest features of the language, but it is a great reference book nevertheless
Absolutely it is.

Go, the language, changed very little since 1.0, most of the improvements have been done on the runtime, GC latency and such.

Mar 04, 2016 · moonlighter on Go by Example
I can highly recommend "The Go Programming Language". I find it extremely well written, and worth every penny.
For sure, it's like the "C and R" for Go. Plus the source code for the examples is on Github.

- Book Site:

- Book Example Source Code:

You mean "K & R" for Go? :-)
Ah, yeah - too late to edit! Please accept my apologies.
+1. Excellent book. Nice pragmatic examples that not only showcase Go's features but are also interesting from the purely algorithmic angle covering pretty decent range from bit-twiddling to some rather involved math (by my standards of course).
I didn't love it. I found it a little inconsistent, and I didn't learn that much from it; most of the Go blog posts have more insight than the book does.

It's a fine introduction to the language! It's great that Go has a credible book. But if you're already familiar with Go, I think you can skip this.

Happy to hear if other readers had different experiences.

I looked forward to a complete chapter on IO (not unlike, but didn't see one.

Perhaps a future edition...

Oct 30, 2015 · 5 points, 0 comments · submitted by ertemplin
Jun 20, 2015 · myg204 on Resources to learn Go
Waiting for this Kernighan piece:
Mar 05, 2015 · 396 points, 253 comments · submitted by davecheney
I've not been a huge fan of Go (more of a Rust person). However, seeing these authors, I'm now itching to get my hands on a copy of this book and give Go another shot.

I wish I didn't have to wait until the summer for it!

Edit: Also, I realize it's unfair to compare Rust to Go, since they really fill two different PL niches. I actually think there is plenty of room for both languages. By my statement above, I just meant that I'm more drawn to Rust's functionally-influenced approach than Go's modern take on the imperative paradigm.

K&R had some wonderfully tricky exercises. This should be fun. (Assuming I don't give up again!)

Edit: Hmm, perhaps I should dust off that copy of K&R and continue from where I left off? :D

I've actually used some of the exercises from K&R when learning other languages, they're so good.

This should be a lot of fun.

Same here with regards <other languages> vs Go, but given the authors the book is most likely worth reading.

Just have to think if I still want the classic hardcover version or go for the Kindle version when available.

Hopefully they'll do one for Rust, too, next.
That's doubtful, as the likely reason that they've written this one is that they're the same group of people that created the C language, now having moved on to Go.

Ken Thompson, one of the creators of Go, worked with Dennis Ritchie (the "R" of "K&R") at Bell Labs, and created B, the precursor to C. Rob Pike, one of the other creators of Go, worked with Brian Kernighan (the "K") on two programming books. These guys are from the same crowd, in other words.

Rust comes from the gang at Mozilla. Different generation, slightly different lineage of thought.

  C --> Unix --> Go
  Netscape --> Firefox --> Rust
Well, no. It was UNIX -> C.
It was Multics -> C -> Unix -> C -> Unix... etc.

C was developed in order for Ken Thompson to write the first Unix. The development of one fed the development of the other and they came into being together.

The early versions of UNIX was not in C. C appeared a bit later. If you would take time to read the history, you would see that C jumped on just with v4.
The C Programming Language had a tremendous influence on me. Everything I've written has been with the hope that I might capture part of its magic.

That said, maybe The Little Go Book ( can tide you over until summer.

Go, with its simplicity, is a gift from the generation of masters to today's professionals, but many of today's professionals appear too ignorant to see the wisdom of the language. It used to drive me crazy when I would read negative comments in r/programming and HN, but I don't even pay attention to the negative comments anymore. The adoption is far better than I was afraid it was going to be.
I agree. And not for nothing, I'm shipping production code, at a real company, with real customers, with real revenue (250m+).

Here's the deal -- all programming languages are just tools. Go's great because it's small enough to keep in your head, and simple. It's fast. It promotes composition. And it has sane concurrency. And quite honestly, I am more productive for the things Go left out then it includes. That's not to say Go is a perfect (e.g. a 'real' debugger option), and it doesn't have to be. If you love Rust, or Ruby, or whatever, great. The programming language landscape is not a zero sum game.

tl;dr Go's a fine tool to get stuff done for a large set of problem domains.

>>it's small enough to keep in your head

This. And the additional effect is that you can keep more of the problem domain in your head as well. I've been in this game a long time, and my experience has been that the simpler the dev tools, the more likely the programmers working on a particular domain will be SME's in that domain.

My experience is that being a domain expert and simplicity of dev tools has absolutely nothing to do with each other. At the end of the day you have to understand the problem in order to implement it.

Whether you write it in Ruby, Java, Go, Assembler really doesn't change this. It just means you may take longer to do it.

And your logic falls apart. If simple dev tools translate to greater productivity then how do you explain the proven benefits of IDEs with all of their "complex" features.

Subject Matter Expert.
"That's not to say Go is perfect (e.g. a 'real' debugger option)"

As a fellow Go coder, I'm actually stunned how much I can get done without a debugger nowadays.

You know, I've heard this a few times recently and it strikes me as motivated reasoning. Yes, built in unit testing and tooling is great. Vet and fmt are helpful. Static typing rocks. But... I would definitely welcome a proper debugger.
I'll be candid with you: You're probably right. I would also welcome a debugger in the long run, and I'm sure I'd change my tune pretty quickly if I hit a big snag in production. :-)
>... it's small enough to keep in your head...

While I mostly agree, the flip side of this statement is, the language then does not automatically take care of things that then you have to keep in your head while you're solving the problem.

I guess this is the underlying trade-off people make when using "higher-level" or "lower-level" languages. More "powerful" languages do more for you automatically, but you need more up-front investment in really understanding the language and applying it to the problem at hand.

And since we are all individuals with individual preferences, whatever choice you make is totally valid for you. It does not make sense to look down on the choices of others. On the other hand, there are some concepts that really are well-understood enough and apply to a large spectrum of languages. These should see widespread adoption, and it does not make sense to deny this either.

The 'magic' that you seem to pine for like is found in lets say Ruby, places a far larger mental burden on the programmer than a language like c or go.

Sure, language like Haskell or Rust have a ton of great features and automagical things but I disagree that they are easier to use. One has to keep far more in your head writing Haskell than Go, a clear indicator of this is the difficulty in learning the language. Like c, you can learn Go in a weekend easily.

I am not saying those others types of languages don't have their own strengths, just that I disagree with your assessment that their features provide a lower mental load.

I don't think you can really learn C in a weekend. Not with all the ins and outs of undefined behavior. And if you don't know your way around the undefined behavior in C, you're going to make dangerous mistakes.
For various meanings of 'learn'. My point is that you can be writing useful programs in c in a weekend.

Obviously said person would not be an expert, but I've watched competent programmers try to learn complex languages like Haskell and Scala; there is a far more complex mental model that one needs to build before they can use those languages specifically because of all the automagic that happens in the background.

> My point is that you can be writing useful programs in c in a weekend.

We'll need to define criteria for "useful program" but I believe most people could write useful programs in most languages in a weekend.

> I've watched competent programmers try to learn complex languages like Haskell and Scala

> far more complex mental model

I think its more that those languages are different, not that they require a more complex mental model.

Can we at least agree here that complexity implies a larger cognitive burden? I think that's a pretty benign statement to begin from regardless of the domain (programming, cooking, games, etc).

A complex recipe rewards a chef with exceptional results if they follow it perfectly, but also presents more opportunities to fail. A simple recipe might not offer the results but it should be easier to produce with a lower chance to mess up.

I think the concept generalizes here.

> A complex recipe rewards a chef with exceptional results if they follow it perfectly, but also presents more opportunities to fail.

Agreed, which is why I prefer to implement complex ideas in Haskell. It catches more potential errors than other languages.

> Can we at least agree here that complexity implies a larger cognitive burden?

Right, but remember simple doesn't necessarily mean easy. The reason I use functional languages is because in my experience they handle complexity better.

> A complex recipe rewards a chef with exceptional results if they follow it perfectly, but also presents more opportunities to fail. A simple recipe might not offer the results but it should be easier to produce with a lower chance to mess up.

> I think the concept generalizes here

I of course mostly agree to both of the above, but I think you are mis-characterizing functional languages such as Haskell which are simple but quite different from languages most are used to.

Having watched both complete beginners and competent programmers try to learn Haskell my observation is that hard part initially for the competent programmer is not building the necessary mental model, but tearing down their existing mental model. People with no mental model going in tend to just look at Haskell, go "I guess that's the way things work", and get on with it. Their real problems first arrive when they then go on to try to learn for example Java which has an entirely different model.
I strongly disagree that features don't lower mental load. For example:

Go's error handling is to put it nicely a joke and requires a lot of effort to manually check every single error condition that may arise. Exception handling makes life exponentially simpler. You can ignore, group and delegate errors at any point which is hard if not impossible to do with Go.

> One has to keep far more in your head writing Haskell than Go

I don't think that's really true. I think that's a subjective description of a feeling whose presence or absence depends not how any objective difference in the quantity of things that you need to keep in your head with either language, but with how well each language fits one's (subjective) intuition.

Mental load isn't an objective feature of a language, its a subjective feature of a particular programmer's relationship with a language.

I can't even believe this is the kind of comment that gets upvoted on HN nowadays. "Go was made by smart old people and is therefore good. If you don't understand it's good, you're stupid and I refuse to listen to you."
fwiw, I found sesteel's comment useful and informative.

(by the way, you might have misread it. I think he didn't mean "generation of masters" as "old smart people" but probably specifically the creators of Go, since they happen to include Rob Pike and Ken Thompson - two people who had separately created the B programming language (immediate predecessor of C), co-created Unix at Bell Labs in the 70's, co-authored a famous Unix book with Kernighan (of Kernighan and Ritchie fame), authored UTF-8 together, etc. They happen to be actual old masters.

They created Go in 2007, from what I heard cleaning up a lot of their old mistakes along the way.)

I know who created Go, because everyone does.

Being created by Pike, Thompson, and whoever else does not in and of itself make Go better than any other language. It also does not make it immune to criticism in such a way that you should brush off anyone who has anything negative to say about it.

>Being created by Pike, Thompson, and whoever else does not in and of itself make Go better than any other language.

which is why I called your parent useful and informative.

It doesn't make it better, but it's a __very strong hint__ that perhaps I should look more closely at Go. Experts matter, and it would be foolish of me as a developer to discount the experience of these guys -- they've literally been programming for longer than I have been alive.

I respect the creators of Go deeply, because they have been so formative of the industry. It's like being an electrical Engineer, and having Nikola Tesla make a suggestion -- I might not understand all of the lessons, but there's a distinct possibility that these guys are addressing problems I don't yet fully understand.

I think this can be misleading.

The guys who designed Go have not designed any other popular languages in the decades between C and Go. They have not produced any modern developer tools or toolchains. Rob Pike's last language before Go was a quasi-DSL called Sawzall, which is a Google internal language for logs processing. I had to use it when I was at Google and frankly, I would have preferred other languages to have been used and didn't find the stated reasons for its creation to be convincing.

If you want to talk to someone who has more modern, relevant experience in language design, go talk to someone like Martin Odersky (Scala) or Andrey Breslav (Kotlin). Andrey in particular has my respect because whenever a language design point is queried he has a well thought out reason for it being that way, often backed by evidence from other languages like C#, Scala, Java, functional languages etc or experience of building modern developer tools like debuggers and IDEs. Both things that Go has a notable poverty of.

In contrast, the justification for Go's design decisions very often come across as arbitrary, or very specific to Google's own codebases. For example Google's C++ style guide bans exceptions, partly because writing exception safe code in the absence of garbage collection is very hard. So not having them in Go won't seem like a big deal to many Googlers. But Go is GCd so that rationale doesn't apply, and the others offered are weak.

Same for lack of assertions. Google has a lot of very, very large slow starting servers and unfortunately at some point some of the engineers on these projects decided that assertions were evil because they had some outages caused by an assertion being hit frequently, causing server restarts. Some code bases there ban assertions as a result. Of course this has a habit of converting a noisy, instantly detected problem into one of silent data corruption or garbage results instead. But it's easier for SRE teams there to measure uptime and response latency rather than correctness of results for obvious reasons, so a bias towards "up but wrong" rather than "down" makes internal political sense.

This of course does not apply to many, many other codebases (in particular, codebases that have exceptions!) and the Go FAQ freely admits that assertions are highly convenient. But the language doesn't have them anyway, because hey, Google C++ sometimes decides not to use them.

> Both things that Go has a notable poverty of.

It surprises me that you say this, since we (the Go team) spend a huge amount of time and energy talking about our design decisions. But you must have missed it, because the examples you give are wrong.

> For example Google's C++ style guide bans exceptions, partly because writing exception safe code in the absence of garbage collection is very hard. So not having them in Go won't seem like a big deal to many Googlers. But Go is GCd so that rationale doesn't apply, and the others offered are weak.

The rationale for not having exceptions in Go is not about safety, but rather readability. When you're programming with exceptions you need to keep in mind a second hidden path of control flow.

I think you similarly mischaracterise the argument against assertions. In essence, the real reason is that failed assertions produce terrible error messages (that's why Go's testing framework doesn't have them either).

While you're talking to Odersky, ask him about Go. (He said: "I like a lot of the design decisions they made in the language. Basically, I like all of them.")

> When you're programming with exceptions you need to keep in mind a second hidden path of control flow

So ? Developers are completely used to it. Every time there is a conditional statement e.g. if/else we have to think about the other control flow. Likewise every time a method calls another method. And if that method is in a different class then you again have completely lost visibility. Developers are constantly dealing with control flows that go everywhere but straight down.

Java is the 2nd most popular language in the world so pretty sure developers have managed to cope with exceptions just fine.

> Every time there is a conditional statement e.g. if/else we have to think about the other control flow. Likewise every time a method calls another method. And if that method is in a different class then you again have completely lost visibility.

None of that is what I'm talking about. In each case you mention here, it is possible to trace execution by following the code. Each statement passes to the next statement in the block, or—in the case of a branch—very obviously skips to another block or function.

Exceptions provide a second parallel path of execution that may or may not be followed, depending on decisions made in places you know nothing about.

> Java is the 2nd most popular language in the world so pretty sure developers have managed to cope with exceptions just fine.

Arguing "it's popular therefore its good," is a waste of time. Some people obviously like exceptions. I'm just stating the reason Go's designers decided against them.

I didn't say Go bans exceptions because of safety. I said the people it was targeted for won't miss them because they have been working for years in environments where they are not allowed for safety reasons, and the stated justifications for not having them are weak.

The arguments about assertions is a typical example of this weakness. A failed assertion in any reasonable runtime and even in google3 C++ produces a stack trace and a log message indicating what assertion failed. It's then usually easy to go read the code where the problem was hit and start debugging.

In contrast, I find typical Go code to be an unreadable mess of nested if statements and C-style return code propagation. Information is routinely lost and errors ignored. When something goes wrong you don't get a convenient stack trace showing exactly how the program arrived at the place where the failure occurred, you might if you are lucky get a generic error message indicating the general subsystem where something went wrong, or if you're very lucky a log message, but several big Go programs I've seen didn't bother with exhaustive logging on error paths and were difficult to debug as a result.

Compare to other languages (nearly all of them) which have exceptions: I've never once been confused or found code hard to read because of the use of them. That's just not a problem I recognise. But I've benefited from them more times than I can count.

I didn't know Odersky said that. I think that's very polite. Regardless, the language he designed looks nothing like Go, so I guess if he really likes Go's design decisions he has decided that his own language got it all wrong. I don't think he's really decided that.

in addition to what logicallee said, it's common for inexperienced programmers to (poorly) "re-invent" concepts that were discovered in the past by those "smart old people". This is caused by a combination of factors, and one of them is the belief that one can solve a problem single-handedly without studying the fundamentals and previous strategies. Ignoring the work of the masters is a good way to start from scratch and do worse.
Sometimes, it's also a way to invent things that were considered impossible.
Yep! Also, reinventing what existed before (intentionally or by accident) can give you a better appreciation for what was invented in the oast and might be the best way of finding out about it (if you don't know the name, for example).
For the record, ignorant does not equal stupid, being a master does not mean you are old, and ignoring negativity (which I should have done here) does not mean I refuse to listen to you. I was simply trying to convey that the rocket has left the launch pad and people will be exposed to the language professionally whether they like it or not. I am finally free of feeling like I need to defend the language to others. It is somewhat liberating.
>For the record, ignorant does not equal stupid, being a master does not mean you are old, and ignoring negativity (which I should have done here) does not mean I refuse to listen to you.

Ignorant might not mean stupid literally, but it still means "you don't know about programming languages" in the context of the comment, which is also bad.

Being a master might not mean you are old, but the masters we're talking about here (Brian et al) are ALSO old.

And saying that you're "ignoring negativity" if you ignore complaints about Go means that you're labelling them as whining or coming from "negative types" instead of accepting the possibility that it can be actual valid criticism.

Thank you for trying to educate me on what I meant by my own comment. Contrary to what you might think, ignorant, in the context of my comment does not mean "you don't know about programming languages" and I know this because it was my comment. I was simply referring to people not having the same professional experiences such that they would appreciate a language like Go.

The crux of the issue is that Go is a local min in a field of possibilities, you may value differently the attributes of various programming langauges which would lead you to some other alternative or local min. I am not passing judgement on others for doing so, but also please be brave enough to admit your ignorance as to why some of us settled where we did with Go. I willingly admit I am ignorant as to why people think other languages are a good idea for general use.

>Thank you for trying to educate me on what I meant by my own comment. Contrary to what you might think, ignorant, in the context of my comment does not mean "you don't know about programming languages" and I know this because it was my comment.

What one means and what one writes/communicates can be two totally different things. The "I know because I wrote it" is a valid argument regarding intent, but doesn't hold the same power regarding what the written thing means to others who read it.

>The crux of the issue is that Go is a local min in a field of possibilities, you may value differently the attributes of various programming langauges which would lead you to some other alternative or local min.

Why would one want a "local min" though?

If anything one would prefer the global maximum or at least a local maximum.

Or is the "min" meant in some dimension that one would actually want to minimize?

You mention the key point of Go: simplicity. I think many developers tend to underestimate the power of simplicity and overestimate the power of certain features. Every single abstraction has a price in complexity. This is why Lisp, being a super powerful language invented in the 1950s never got widely used. Even when the syntax is simple, the conceptual complexity of the language is quite big. Same thing happens with Haskell and at some point with Rust. In the end people realize you can actually build things up without paying this complexity tax with simpler languages. This is why languages like Go succeed.

Note: Rust actually has a chance because it's simple compared to its competition: modern C++.

> Even when the syntax is simple, the conceptual complexity of the language is quite big.

Lisp is a very simple language conceptually. The problem is that it allows you to build insane amounts of complexity in a very "free for all" way. No "one sane default way to do it".

The problem is now how complex a language is, but how much needless complexity it allows you to build yourself.

Go seems great because it doesn't easily allow you to build needless complexity. Though I've never coded anything meaningful in it, so my praise for it would be armchair thinking...

>The problem is now how complex a language is, but how much needless complexity it allows you to build yourself.

Any Turing-compelete language allows you to build arbitrarily much needless complexity. I don't see how it's a useful metric at all, except to say, "Well, this language isn't quite so horribly stunted that you can't even produce a nonterminating program."

If you want to talk about how easy it is to build needless complexity— well, I've yet to see a programming language that knows the difference between necessary complexity and needless complexity well enough to allow the former and prevent the latter. Rather, languages either let you build complex things easily, whether you need that complexity or not, or they just make it a right pain in the ass to accomplish anything.

Personally, I prefer the languages that let me express the complexity of my problem domain easily; sure, I could use them to make things more complex than they need to be, but I don't, because to be quite frank that's just part of being a competent programmer.

Are you talking about Common Lisp, or are you talking about Scheme? Common Lisp does provide primitives for just about everything, in ridiculously generic forms. Scheme forces you to code it yourself.
> Common Lisp does provide primitives for just about everything

Most of it are not primitives though, Common Lisp only defines 25 special forms. Guess how many keywords Go has?

I would see more 'primitives' in a language than 'special forms'.

For example Common Lisp provides support for complex numbers and operations for them. These operations are 'primitives' in the language. This is unrelated to 'special forms'.

I think the criticism leveled would go to both. If what you say is true, moreso to Scheme. But the criticism is more that it allows this. To many, it even encourages it.

For myself, I still like it, a lot. To the point that the more I learn of it, the more I'm confused on how it hasn't taken off better.

Both haskell and probably most lisps are relatively simple languages, compared to python, ruby, c++, etc. I think I have some idea of what you're saying but I'm not familiar with go.

> Every single abstraction has a price in complexity.

I think the whole point of abstraction is to lessen complexity; wrap up many different things into one thing that's easy to reason about. Very few languages support creating good abstractions, unfortunately.

> I think the whole point of abstraction is to lessen complexity; wrap up many different things into one thing that's easy to reason about. Very few languages support creating good abstractions, unfortunately.

Abstraction lessens complexity, and also adds complexity.

Take monads in Haskell, for instance. Let's oversimplify and say that absolutely everything is done through monads. Great; we've now wrapped up many different things into one thing that's easy to reason about. And when I want to do something, I don't have to think at all - I just reach for a monad.

And then I have to think, because now I have to figure out how to make a monad do the specific thing that I actually want it to do.

Or I'm reading the code, and yes, that's a monad, because it always is, because everything's done through monads. But what is this monad at this location in the code actually doing? Well, I have to work my way back out of abstraction to concrete in order to understand that.

One way to think about this is abstract art. As art gets more and more abstract, at first I can't tell whether I'm looking at a blonde or a brunette. Then I can't tell whether I'm looking at a male or a female. Then I can't tell whether I'm looking at a human or a chair. And finally, I get to the point where I'm looking at a painting that could be anything, but it's impossible to say what it is. Abstraction has proceeded to the point that communication (between the artist and the viewer) has been lost. In the same way, abstraction in code can proceed to the point where communication between the author and reader is lost, and then it takes a lot of work to wade through the layers of abstraction to find out what the code is actually doing.

That would be true if abstraction were a cosmic force that radiated in all directions equally, a Hegelian horror trip anihilating all meaning so to speak.

But most of the time, we are abstracting away something specific in order to make something else more concrete and less obscured by irrelevant detail, hence reducing complexity.

Of course abstraction can go wrong, because sometimes we abstract away things that are very relevant, perhaps in futile pursuit of future code reuse. But having the tools for abstraction does not make abstraction go wrong. We do.

I think HN might find discussions more productive if commenters were more specific when they discussed the simplicity of their favorite tools. Qualifying an entire language as "simple" isn't very descriptive when the word often describes totally opposite languages.

When someone talks about a language, I'd rather they talk about what exactly it is the language simplified and where it hid the rest of the complexity. One can only simplify a Turing Complete language so much before the it starts running up against the limits of Kolmogorov Complexity. After that point, the best we can do is shuffle it around - under the bed, or under the sofa, or inside the closet, or into a corner - depending on each programmer's preferences.

When people talk about abstraction for example, they really mean reducing mental complexity. The pro is that we can reason about a larger percentage of our programs by being able to fit more code into our limited working memory. The con is that something other than our brain (e.g. algorithm w) has to do the heavy lifting. With abstraction, all the little details (the complexity) still exist somewhere, we just don't have to look at most of them.

Not that I can completely disagree with your point, but there are many reasons outside of the intrinsics of a programming language that can and will influence ones success.

The marketting muscle that was put behind Java certainly helped it in its time. Same for the actual market that backs objective c.

C probably benefited as much from the open distribution as it did anything else. Combined with a relatively high quality compiler that was heavily distributed (gcc), this can not be understated. The only languages that were as highly distributed were probably the various BASICs, and there are obvious reasons to fall off of those at some point.

So, you can blame lisp's lack of popularity on its complexity. I am not so sure that is a good foundation, though. I feel it is as much lack of a high quality distribution of it as it is anything else.

Though, highly on topic, it should probably be noted that the approachability of the original C Programming Language book that is making so many people excited about this book probably had a very heavy influence, as well. I am not so sure a book can have as heavy of an influence in today's environment, but I think it would be foolish to discount the amount of influence a publication like this could have had back in the day.

I don't think GCC can take any credit for C becoming a popular language. GCC 1.0 was only released in 1987, and prior to that most people were stuck using proprietary compilers. I would rather say C succeeded because it was tied to Unix, and Unix was very successful.

GCC certainly contributed to C continuing to be widely used.

Quite right.

Before UNIX became part of the enterprise workforce very few cared about C.

My feeling is that it is fair to say that gcc contributed to linux existing, and linux has had a large positive influence on c's current life.

That said, you are definitely correct in C's early popularity. And that probably contributes more heavily than later items. (There is a term for this, but I can't remember it right off.)

There is no "Lisp invented in the 50s" that never got widely used. This language doesn't exist. To use that level of abstraction, replace every language in your post with the word "Algol" except Haskell which you call "ML". Doesn't make sense? Neither does your reference to Lisp.
In the end people realize you can actually build things up without paying this complexity tax with simpler languages. This is why languages like Go succeed.

Of course, you pay the tax somewhere else and that is code duplication. You see this in Go due to the lack of generics, which often results in duplication of code for different types or reliance on reflection (which is slower and can lead to runtime errors).

This is not a critique of Go, just to point out that it is a trade-off, and there isn't necessarily one right answer.

But that is so rarely an issue... You might encounter an occasional specific circumstance where you will need do some code duplication in Go, but I've written many thousands of lines of Go and have had to resort to duplicated code once (and in that particular case all that required was a couple copy-pastes and minor edits, and I'd have to go back and revisit it but it's possible I could have solved it more elegantly if I'd known Go better).
But that is so rarely an issue...

For you...

It depends on what kind of code you are working on. If you work a lot on numeric code (e.g. in machine learning), you want to make it easy to specialize on e.g. 32-bit or 64-bit floats.

Also, since only built-in types are generic, you cannot implement other containers (you never need binary search trees?) in a safe manner.

So, yes, the lack of generics is a frequent issue for me.

Yes, and that does not conflict with what I was saying. There are specific problem domains where generics would simplify matters, but in the overall universe of problems those domains are rare, i.e., most of the code that most programmers will write in Go will not involve duplicating code because of the absence of generics.
I can't remember the last non-trivial c++ program I wrote that I didn't use generic containers like std::vector or std::unordered_set, or the last java program where I didn't use List.
I think you slipped in a subtle but annoying mistruth here: "in the overall universe of problems those domains are rare" is just not true. What is true is that the kinds of programs Go programmers typically write may end up not needing this sort of polymorphism, which is very different from saying "domains where this sort of polymorphism is important are rare".

I only point this out because I've seen a lot of Go programmers defend Go by saying parametric polymorphism is only really important in particular niche domains, when really they want to say that Go only focuses on a particular niche domain where it isn't important.

Yeah, but aside from the singular issue of generics (which are not exactly cutting edge), I can't think of a single 'advanced' feature that would add nearly enough utility to pay for its additional complexity. Everyone who shows up complaining about how it isn't "moving forward" by embracing features of high complexity and dubious utility is really missing the point IMO.
Well, they're really missing the point of Go.

It's fine for languages to embrace those features, and be what they are, and it's fine for Go to reject those features, and be what it is. We don't need "one language to rule them all".

My low content response is that you are brutally correct.
What about sum types (discriminated unions)? Sounds like that would help make error handling a lot safer and easier.
How do sum types make error handling safer (without also adding exhaustive pattern matching) or easier (without adding do notation or macros)?

The point I am trying to make is that adding some features from other languages doesn't provide sufficient value without also adding other features. Adding all of them can make the language significantly more complex that you wonder whether the benefits gained are worth it.

The problem with omitting language features like this is that the programmer is then forced to implement them by hand in an error-prone way. It's the same issue with Python and tail call optimization. Guido refuses to implement tail call optimization, so the programmer has to implement it herself in terms of a loop. Go refuses to implement sum types, so programmers code them up by hand. In neither case is the code actually clearer.

Since proper error-checking in Go actually requires doing by hand what a pattern match would have done anyway you're not simplifying anything for anyone by omitting them; you're just making it harder for the compiler to provide compile-time checks.

A pattern match is basically a switch statement. Go already provides the latter so the language would not need to become more complicated.

This exactly what I mean when I say that people underestimate simplicity and overestimate features. Yes, generics are a nice feature. Yes they help you to avoid code duplication. Yet, not having them is not a stopper at all. Programs are shipped without generics. Code bases remain clean enough without them. On the other hand, every time I read a generic function in C# or Java I feel I have to double think everything. That's the price of of adding an abstraction layer.

Don't get me wrong, I like generics. I think they would be a nice addition to Go. But I understand Go designers when they try to be conservative about it. I like that they only add features when it's absolutely obvious that the pros overcome the cons.

This is the first time I've seen the Blub Paradox [1] portrayed as ignorance from the other direction!

OK, not a big believer of the "Blub" theory, personally - every language has its place in a continuum of dimensions that are more than just technical, and I actually like Go overall. But "lack of generics" is definitely not the same as "simplicity. Not in the decade we live in.


The Blub Paradox would only apply if the people using Go hadn't used languages with generics (or similar); for the most part that's not true.

> But "lack of generics" is definitely not the same as "simplicity.

It's not literally the same thing, but it is an aspect that keeps Go simple.

"The Blub Paradox would only apply if the people using Go hadn't used languages with generics (or similar); for the most part that's not true."

Yes, speaking for myself as someone often in the position of defending Go on HN (even though as a computer language polyglot it isn't part of my personal identity), I also speak several other languages that do have generics in them, along with substantial usage of the "dynamically typed" languages, and most relevantly, including reasonable fluency in Haskell, a language where the generics are so deep and fundamental they aren't even given a name, they just are. What Haskell calls "Generics" is actually more like what other languages call "reflection".

Yes, there are a ton of programs that you can usefully write without "generics", especially since interfaces are about half of "generics", and arguably the more useful half in general. Yes, there are a ton of programs that you can't really write without them. We could do with a lot more sensible discussion about which programs are which and a lot less "Oh, you think it's OK for Go to not have generics? Well you must be an idiot then." (e.g., my frequent observation that if you need a rich numeric hierarchy you really need generics... but those cases really are exceptions compared to programs that are just fine on integers and floats, and, frankly, in many cases just fine on integers alone.)

This might be the first to-the-point comment I have read on HN that gives a clear perspective on the differences without being arrogant. Needing or not needing a rich numeric hierarchy is a great way to summarize it, I think. All of the hate towards a lack of generics really makes me wonder what programs people are writing that they feel they really need them given the fact that go does have interfaces. Nice post!
I've been coding Go professionally now for about 8 months. Interestingly, it has made me appreciate C++. The reason is while the Go compiler is fast, it is mostly because it doesn't do very much work. By contrast, a C++ program takes a long time to compile because the compiler does a lot. It's obviously not as black/white as I've portrayed it here for brevity, but it is nevertheless an apparent trade off.

I like Go overall, but on balance I would prefer a slower compile-test cycle to have more language feature support.

> on balance I would prefer a slower compile-test cycle to have more language feature support

So, are you sbt as in:

? I don't think i've seen a build tool posting on HN before, but now i have, i'm not surprised it's a Scala one.

My only real issue with it is that I really with it had algebraic types. That would save me a tonne of faffing about and help make code safer to boot. Type switches are a clumsy alternative that only cover some of the cases.
Specifically to be utterly pedantic: Go has algebraic types. It has both Product types (structs) and unbounded Sum types (interfaces). What you're looking for is bounded Sum types with extra language support such that when you use them, it checks that you've covered all cases.
Two words: error handling and generics.
Go's error handling is honestly the best I've ever used. No errors go unhandled. Period. get an error? Return it or deal with it. Makes much more sense than exceptions suddenly breaking the behaviour of the language.
How are errors in deferred functions handled? How about division by zero?
errors in deferred functions are handled just like they would be if the function were not deferred. There are some things like division by zero and array index out of bounds that cannot be used with this method without making the language incredibly cumbersome... for those, there are panics (basically like exceptions in other languages)... but they happen quite rarely in practice.
Deferred functions can pass along errors by using a closure.
It's not actually true that no errors go unhandled.

    func foo() error { return errors.New("whoa!") }
    func bar() { 
        _ := foo()
        // onward!
Uh yes? This is you telling the compiler specifically that you don't care about the error. It's equivalent to

    try {
    catch {}
In other languages. That's not a problem, that's the computer doing what you explicitly told it to do.
Not quite: here's an example of code which returns an error but for which the return value is never even captured.
I think you have a misunderstanding of exceptions. In JVM languages for example you have two types: checked and unchecked. Checked exceptions force you to handle errors immediately just like Go. Unchecked doesn't.

There are many situations in which you want errors to go unhandled and bubbled up to some common error handling logic.

Exceptions IMHO are vital. They standardise error handling behaviour across your application and provide flexibility in when, where, and how you handle groups of errors.

I agree, those are two great reasons to use Go.
Totally worth the downvotes for my own amusement. :)
Why down vote some who likes the fact that he likes the error handling method in Go and that he doesn't like generics?
that's 4 words .... and if you are not comfortable with those two aspect of the language and have the choice, I don't see why you need to use golang.
Error handling is something that I did get used to, especially considering that one can assign and check in an if-statement.

Generics I still miss every single day.

But not enough to stop using Go. It's pretty much C with interfaces, a garbage collector, and safety. What more can one wish for?

No garbage collector so I can actually use it in embedded situations.
I should stop using rhetorical questions :). But indeed, such embedded applications are not Go's domain.
Easy target response I know, but hey it's open source so fork it.
That's not really what Go is for. Look at Rust if that's what you want - memory safety without a garbage collector.
Have you tried go gen? It looks clearer to me than some of the hoops I've seen set up, jumped through, etc for heavy STL generics:

It just creates the code for you, then you commit it. Easy enough.

Code generation tools like go gen are good for those situations where you have boilerplate code based on the structure of your type, like serializers, comparison functions, etc. On the other hand, these tools do not help you create abstractions or decoupled interfaces.

An analogy would be the "deriving" system in Haskell. It doesn't replace the generics system, it just complements it.

It just creates the code for you, then you commit it. Easy enough.

Except that it does not provide the same thing. If I provide a package with e.g. a container datatype, I would have to generate for every possible data type that any user wants to put in the container.

Obviously, that is not going to scale.

Not really.. you provide the base code, and the consumer of your package generates the specific types they need. As the package author, you don't actually generate any of the concrete implementations.
Which defies the whole point of easy go-gettable packages.

gen is a good contribution, but it only works for a subset of cases. E.g. I follow a comparable approach in my Java library for finite state dictionaries because Java does not provide generics over primitive types (luckily, that is a closed class). But it's less than ideal.

Simple languages are good, but we should be careful to understand why they are simpler: in many cases, the complexity is simply shifted from the language onto the programmer.

Though simplicity of the language is important, I feel that the ability of a language to manage complexity is more important. It is probably one reason why many people (myself included) have some issues with design choices made in Go.

> the complexity is simply shifted from the language onto the programmer.

That's not my experience with Go at all - it provides less resistance to getting code written than any other language I can think of offhand.

Maybe, if there were several official "levels" defined for complex languages (like Scala). So then a team that wants to keep codebases conceptually simple could decide that they are only using features up to e.g. level 3, anything above is forbidden. And the compiler would support this.

A bit like you can select different languages in Dr. Racket

but I don't even pay attention to the negative comments anymore

The "not quite a field" of programming, has a famous history of being full of smarmy naysayers being spectacularly wrong. It's no wonder that the few of us who aren't bratty and quickly judgemental tend to become famous and successful. (Nor that a famous blogger once said that everything he needed to know about managing programmers, he learned from the book, "How to Talk to Your Five Year Old.")

Maybe part of the problem is that people that promote Go in some capacity will at times make good arguments for certain things, but when they find something that they can't really explain, or that might seem subpar, they devolve their argument into some kind of appeal to authority - 'who am I to question their decisions. These are experienced, respected programmers with a lot of accomplishments. Who are anyone born after 1985 to judge them, really?'

So maybe you'll excuse some people for not simply assuming that the masters are right just by virtue of who they are.

While I do agree that just saying "Well, Rob Pike and Ken Thompson must know what they're doing" is not a valid argument. I actually don't see many people making that argument. However....

There's authority, and then there's deep domain knowledge.

If I was in the market for a bicycle, and Lance Armstrong had built one, you better believe I'd at least try it out. And even if I didn't entirely understand why he built it the way he did, I'd probably just assume he knows WTF he's doing.

Note that the whole reason this HN thread exists is not because some random book on Go is being published, but because Brian Kernighan's name is on the cover.

> Note that the whole reason this HN thread exists is not because some random book on Go is being published, but because Brian Kernighan's name is on the cover.

Fame is a good enough reason to give things priority when it comes to checking it out. But it is not a valid reason for saying why it is good to begin with. There's a difference between saying "I might buy this book because it is written by X", and "This book is good since it is written by X".

You might find this interesting: , my reply to someone's question about what is interesting and/or unique about Go. A bit much to just copy & paste in here, probably.

While so many people are complaining about what it doesn't have, there are things it does have that, while not individually unique, are actually packaged into a unique bundle. Particularly the fact that it is a traditional imperative language. If you (like me!) don't mind picking up Haskell or O'Caml or Erlang to get weird features, it might be hard to understand the appeal, but for many people Go is the first time they've seen these features without having to drop almost everything they know about programming on the floor in the process. This probably explains some of the breathless excitement it sometimes engenders... it's the same breathless excitement that people will sometimes have when first using those other languages.

(And, yeah, the traditional imperativeness does bite a bit. I'd love to be able to assert that a goroutine is fully isolated from everybody else's memory. In practice, I'm not having any trouble with that, but, then, I've got 7 years or so of Erlang under my belt so designing isolated processes that work together via clean interfaces is something I've got a ton of experience with from the most rigid language on this topic there is. YMMV, and I really mean that... you certainly can blow your foot off in Go, isolation is only convention, not enforced.)

While so many people are complaining about what it doesn't have,

The problem is not really what Go does not have, it's that often fallacies are used to react to critique on Go. Another one that pops up very often is 'you just have to use it for some time to understand why Go does not need it'.

This is of course nonsense. Anyone who has programmed C and C++ knows the advantages and disadvantages of generics. And despite the disadvantages of a particular implementation, most people want still want generics for good reasons.

Even if you like Go (and I do mostly), it's ok to say 'sure, that is a weakness in the current version of Go'.

Read what I linked. I'm not afraid to anti-recommend Go for given use cases.

That said, since you mentioned it, I'll reiterate what's in that link to observe that "Go doesn't have generics" is a half truth. (And I don't mean "lie"... it has non-trivial truth in it. But it is only a half-truth.) Generics are a complicated concept that encompasses at least "generic data structures" and "generic algorithms"; you can slice and dice in other things, too, but it certainly has at least those two aspects. The former I freely admit is an uncovered case, and I still believe is something Go needs to address sooner or later. The latter is covered in Go via the interfaces.

I think the reason why Go in practice doesn't need a lot of generic data structures is that its core use case, concurrent network servers, has an awful lot of byte streams flowing around, and, lo, the code I'm converting into Go has a lot of byte streams flowing around. A bajillion "generic data structures" don't much help with that use case. (Now, the natural contrarian argument here is to talk about how you might need them someday, but, seriously, you probably don't need them all the time. If you do... don't use Go.) The "generic algorithms" concept is incredibly useful, but, lo, Go actually supports it fairly well. On first read of the Go feature set it's really easy to blip over the "implicit satisfaction of interfaces" and think it's an irrelevant parlor trick, but in practice it's really very useful in surprising and profound ways.

Thanks. That was a good comment.
Can you please elaborate on the "wisdom of the language" and why you feel it's necessary to ignore all criticism?
> ignore all criticism?

I don't feel like they ignored them they are basically saying they think they have a better solution.

Aerosmith was hot in the 1970s too.
Regardless of how I feel about Go as a language... I don't trust Google to perform well as the steward. It may be open source, but that means nothing if people stop working on it.

If it doesn't become popular, I think they will just let it die. If they start trying to make it popular, I think there will be a big push back from the great unwashed masses of people who want obvious features and then it will die. Only time will tell.

Who's the steward of your language of choice?
Languages of choice...but shouldn't matter who it is. Why draw comparisons that will only serve to evoke political and ideological responses? I think that my suspicion of Google's capacity to perform here is warranted and that's really all I have to say about it.
I don't think you have to trust Google, you just have to trust the core team. While they all work for Google now, the language is open source and they have reputations that extend well beyond their time at Google. I share your distrust of Google, but I trust Ken Thompson, Rob Pike and the rest of the team enough that I don't worry about choosing Go. I have faith that if Google kills it or starts to misbehave, the team will leave and figure out a way to keep the language moving forward.
I understand what you're saying but I think it also goes to my point - I feel like those handful of people couldn't possibly do as much to get Golang into the mainstream as could a whole company/divisional effort. I honestly don't feel like Google as a company is putting that much effort into Golang and many of their other projects.

Remember when they were building Chrome and how quickly they iterated on it? That was awesome to behold! Maybe a slow pace and a smaller user base is better for developing a language, but if that's the case then I guess I'll just wait another decade before really investing time into Golang.

Sounds a lot like you drank the Kool-aid.
>Sounds a lot like you drank the Kool-aid.

So anyone who likes Go is deceived? Why use words like that? How about just saying GO isn't for me. Saying any more is just you imposing your opinion on someone else and devaluing them.

>Go, with its simplicity, is a gift from the generation of masters to today's professionals, but many of today's professionals appear too ignorant to see the wisdom of the language.

It's mostly the wisdom of the eighties. Today's professionals have better options.

I think it's rather the height of hubris to accuse your contemporaries of being "ignorant" because they disagree with your assessment of this particular tool.

Go is an interesting shift in language design, basically discarding many modern trends and techniques and returning to a much simpler paradigm. It's a totally valid approach with lots of merit — complexity can be a killer. In addition, the concurrency primitives, decent stdlib and tooling make Go pretty great to use in some respects. It's likely to be well-supported for a long time and is a suitable tool for many tasks.

On the flipside, using it often feels like a bit of a slog. Error handling is simple (good) but repetitive (bad). Keeping generics out of the language avoids complexity (good) but results in repetitive and awkward code (bad). Lack of features like pattern matching and higher-order functions makes some code irritatingly tedious to read and write. And so on.

Point is, it's perfectly valid to look at these decisions and say "I don't like Go because it is missing these features", as much as it's valid to say "The simplicity of Go is a useful feature". Ignorance is not a prerequisite for disagreement.

So please have some respect for opinions which differ from your own, and think about offering something a little more constructive than insults.

I agree, I should have grounded the claim of ignorance in a long list of specific instances or made no comment at all; sometimes less is more.

Aside, I use and enjoy languages other than Go; it is simply a tool to solve problems, and I don't want to detract people from using other tools. We all develop opinions with regards to what does and does not work well. I never intended to devalue others' experience or perspective. I was simply pointing out that many people seem to not have suffered through enough bad work experiences to appreciate Go's main feature of simplicity.

If you haven't run across horrible, insanely overcomplicated, code written by those that think they are the top 1% intelligence-wise, you might not appreciate Go. Likewise, if you write horrible, insanely overcomplicated, code and think you, yourself, are brilliant, you probably won't appreciate Go. If you only work alone or on small teams and projects, you might not appreciate Go.

Minor corrrection: Go supports higher-order functions

(They even have a codewalk that mentions this in its introduction)

"Ignorance is not a prerequisite for disagreement."

This is a very memorable and useful quote. Thanks for saying it. It deserves to be a classic, in my opinion.

Except that it is not always true. Ignorance is a prerequisite for disagreement if you assume entirely rational decision-making. Without ignorance, if you have disagreement, you very likely have irrationality instead.
"Ignorance is a prerequisite for disagreement if you assume entirely rational decision-making."

You'd also have to be profoundly naive to ever assume entirely rational decision-making out of humans, though I get the sense that a number of those words must mean very different things to you than they do to most.

Is rationality incompatible with subjectivity?
Of course it is. This is probably expressed most clearly in Bayes' Theorem.


> Ignorance is a prerequisite for disagreement if you assume entirely rational decision-making.

This is only true with identical utility functions for all participants. Rational decision making means each actor acts with perfect information about expected utilities of all options and chooses the option that maximizes their own realized utility. Rational actors can easily disagree without ignorance, since rational actors can have different utility functions.

Only if they are ignorant of each others' utility functions.
They can disagree in which programming language each prefers without ignorance of each others utility functions, or on questions such as "which programming language is best for X purpose?".

While there are some questions where ignorance of each others utility functions could produce disagreement, I can't think of any where it is necessary for disagreement.

Just a note: Go supports higher-order functions
complexity can be a killer

Complexity is also the mind killer. However, it kills with ten thousand cuts, not with one fell stroke. This is why the prideful are even more vulnerable!

Go seems to have designed to make compiler beautiful and simple. There was even a brag post about how one of the authors saved few bytes by making a change in the language. My view is that language should be designed to take away repetitive tasks from developer rather than make language pretty or compiler super efficient. It's OK to make compiler complex to meet the demand of important feature that developers would enjoy and want every day.
Citation needed. This is flat out wrong.
In an essay titled "Why Pascal is Not My Favorite Programming Language"[1] Brian W. Kernighan wrote:

  The size of an array is part of its type
  If one declares

     var     arr10 : array [1..10] of integer;
             arr20 : array [1..20] of integer;

  then arr10 and arr20 are arrays of 10 and 20 integers
  respectively. Suppose we want to write a procedure 'sort' to 
  sort an integer array. Because arr10 and arr20 have 
  different types, it is not possible to write a single 
  procedure that will sort them both.

  The place where this affects Software Tools particularly,
  and I think programs in general, is that it makes it 
  difficult indeed to create a library of routines for doing 
  common, general-purpose operations like sorting. 
People who complain about the lack of generics in Go are making the same argument that Kernighan made against Pascal viz. that it is tedious to write library code in the language.

EDIT: Also it is not uncommon for a feature that is deemed essential by some to be thought of as adding too much complexity by others. For example,

  "I've seen [visual] editors like that, but I don't 
  feel a need for them. I don't want to see the state 
  of the file when I'm editing."
said Ken Thompson [2] when comparing line editors like ed to visual editors like vi or emacs.




So, something like that?

Interfaces, man. They're better than you think.

And in a wonderfully ironic twist, you've completely missed the parent's general point while addressing the specific issue they used to illustrate it.

Data structures are the obvious use for generics. There are also things like monads and so forth, used for example in Rust's result type.

Yeah, fuck this type safety and performance thing...
It's type safe and there's little performance hit. Please note that the "Interface" there is not "interface{}" ... it is a somewhat unfortunately named interface:

The Go authors were following a practice that seemed like a good idea at first, and they've now admitted was probably a mistake... i.e. if your package is mostly about a single interface, name the package something informative, and call the interface type "Interface". This works relatively well from calling code, since it'll be referenced as "sort.Interface", but it makes the documentation for the type potentially confusing.

OK, thought you meant the interface{} thing people go for, since Go doesn't have generics.

This Sort.Interface thing is indeed safe and performant. On the other hand its not a solution to the problem we're discussing (that, to quote the parent, due to lack of generics "it is tedious to write library code in the language"). You still have to implement it all the time for all types despite having identical implementations.

So this doesn't show how it's not tedious. It just shows that it can be done in some way, which nobody doubted.

It's not very friendly to the optimizer though. In order to achieve the same performance as a templated generic version by eliminating vtable dispatch, the optimizer needs to (1) convert the recursive sort function to a loop; (2) inline the sort function; (3) promote the interface to the stack via escape analysis; (4) SROA the interface; (5) constant-propagate the SROA'd functions to their use sites; (6) inline the now-constant functions. You need a pretty powerful optimization framework with a well-tuned pipeline like GCC or LLVM in order to do all of that.
Sorting is not the best example of Go's simplicity: it involves creating a new type, implementing methods on that type to satisfy an interface and casting the original collection to the new type (I count four concepts). Contrast with a language like OCaml or even C where you pass a function (one concept).
The language has decent interfaces for things like sorting. Why is it a problem? Declare a method for your type and you're off to the races.
The same could save for assembly over any other language.

Write your own macro-assembler constructs and you're off to the races!

In a funny twist of history, Kernighan is now writing a book on a language where the length of an array is part of its type:
To be fair, slices solve that problem completely:
Technically true, but the point is that arrays were the only collection type in Pascal, whereas Go also has slices (which, in my experience, outnumber arrays 10-1 in most codebases).
When did Pascal gain dynamic arrays?
Depends which Pascal you mean.

The Extended Pascal ISO standard which does include dynamic arrays is from 1990.

Turbo Pascal and other Pascal dialects also had them.

Not true, otherwise Wirth would have had an hard time to write "Algorithms and Data Structures".
Oh. Thank goodness for that.

Now I can resist every publisher that wants me to write a book on Go, and tell myself that was OK to do because I'd never write as good a book as those two.

What modesty!
What you call modesty I call self-awareness.
For those of you who are not familiar with "The C Programming Language" (also written by Kernighan), see:
I have mixed feelings about Go.

For those who didn't try it yet here are the biggest advantages of Go:

- it's totally easy to learn and can be mastered in a day

- it's fast and typesafe

- the concurrency model is great,no question

- I personally like the error system, no exceptions but you can still "bubble up" errors with multiple return types

- it has, in my opinion a comprehensive standard library,you can even do websockets and image compression with it.

The draw backs :

- no generics clearly the biggest drawback, which means a lot of copy and paste

- the lack of idiomatic way to deal with dependencies(no defacto package manager)

I think the ease of use justifies Go adoption in any team. It doesn't replace ruby or python for web programming ( little value in coding a CMS in Go , rails makes more sense),but when it comes to backend or webservices, it's a killer tool.

compared to java, it's as fast and consumes WAY less memory.

I'm in a similar boat. I've tried Go, and partially agree with your sentiment that the ease of use justifies usage of it in any team. Even with its flaws, it's a tempting feature. But I'm not sure if bringing -anything- into an existing stack should be done lightly though since someone has to maintain whatever is brought in. Even if the ramp up time is shorter than usual.

For backend/webservices, I initially tended to agree Go is a killer tool. But if you are a Python shop, why would I bring this into my stack instead of using PyPy (or soon, Pyston) for CPU-intensive tasks? I say this as someone who has never really ran into issues with Python performance, but am looking towards learning Rust once it hits 1.0 for writing my first non-Python library because if I can find something CPU intensive enough, I can justify deep diving on Rust.

Doesn't mean I won't ever run into performance issues, but even Rust may not be necessary (for me), with PyPy/Pyston around. Go itself is more a replacement for other tech, rather than complimentary, which in my view is the biggest drawback not on your list. I like things with big ecosystems that work well together so you're not stuck on an island, and the Python/C(++)/Rust world has great interop. Unless you're a true Go diehard about the language for whatever reasons, this isn't really what I think many like myself are looking for. I see more value in simply adopting another implementation of a shop's existing platform, if you have so many options at least.

I'll be really interested to hear responses to this, as I don't feel interop with Go has been discussed often. Seems people who really like Go are either 'all in' or not at all, figuratively and literally.

> For backend/webservices, I initially tended to agree Go is a killer tool. But if you are a Python shop, why would I bring this into my stack instead of using PyPy (or soon, Pyston) for CPU-intensive tasks?

Two big things here, for my applications.

1. Memory. You mention CPU use, but memory use is even more critical for what I do. For game servers, for example, lower memory usage for an application can change the multipliers on how many users I can handle per server. This can make a dramatic (like 20x) difference in what you can offer users for free vs charging.

2. Static compilation. This makes a massive difference over Python in terms of catching and correcting problems at compile time vs run time.

> 2. Static compilation. This makes a massive difference over Python in terms of catching and correcting problems at compile time vs run time.

Correct. When comparing a static programming language to a dynamic one such as Go vs Python, this is a critical difference. It impacts system stability (production outage rate) and code maintainability a lot, the two characteristics a long-running product desperately needs.

But Go is not comparable to C. Go is garbage-collected, so unlike Rust, it is not a true system programming language (i.e. not low-level enough). On the other hand, it is not high-level enough. It lacks many advanced language constructs, and its type system is rather limited. Simplicity is a big merit of Go, but it's too limited IMO.

Go solves many software development problems for large engineering teams, so I think its ecosystem will keep growing for a while.

Don't forget about the tooling: unit testing, benchmarking, generated documentation, code formatting, and emacs+vim plugins are included in the official package. I think these are often overlooked when describing its benefits. You can jump in and start working right away.

In discussions about error handling in Go, I rarely see mention of panic used for private exception handling. If a module exposes a small surface area, the public entry points can recover from panics and return them as errors. Private functions can then use panic to report errors:

  func PublicEntryPoint(input string) (output []byte, err error) {
    defer func() {
      if e := recover(); e != nil {
        output = nil
        err = e
    err = nil
    output = privateFunc(input) // no need to check for error here
  func privateFunc(input string) []byte {
    foo := otherPrivateFunc(...) // no need to check for error here
    // ...
  func otherPrivateFunc() int {
    // ...
    panic(fmt.Errorf("Something is wrong"))
I would panic-recover a specific type of error instead of the generic "error" type, but I'm simplifying for the example. Also, it is not recommended to panic across module boundaries.
I sort of agree with the go authors that there is not idiomatic way to deal with dependency management at all. (see: They all have their ups/downs and mostly it has to do with the language they are supporting.


+ transparent code on download

- virtually impossible to mirror

- executes arbitrary 'script' blocks that install stuff on your system

- subpar transitive dependency management scheme


+ great transitive dependency management

+ private repos/mirrors are easy with well supported tools

- black box byte code with no licenses

- overly complicated software (ivy/maven)

Python (pip):

+ simple and easy

- virtual environment hell

There are things that i like and don't like with go get:

+ dirt simple and used from the command line

+ code comes into src/. This means that you can see the code and the licenses that you are pulling in. This makes it easy to inspect code in your project. I don't have a hidden code repo in my home directory or some crap.

+ I can clearly see the licenses that i'm pulling in. If you have a GPL in your project it's pretty trivial to audit this (unlike other tools were you have to track down the homepages of 20 random people).

- code is pulled from HEAD. Frankly this sucks. Hopefully people get their act together and release their software and got get will be able to pull a release. I can see the advantage of pulling from head if you're constantly iterating and monitoring for fixes. However, pulling from HEAD introduces the risk that there is a major untested defect in what you just pulled.

Overall as long as there is not a huge chain of dependencies in the code that you're pulling, and as long as you're relatively confident that HEAD isn't going to bust you release, it's a great system. Honestly I think that it makes the developer more wary about pulling in random half-baked code from the internet into their project. Maybe that's a healthy thing.

go get first searches for a go1 branch or tag and pulls from that, if present. master branch is only a fallback.
Is it truly typesafe if the interface{} idiom is commonly used in lieu of real generics?
The lack of a package manager is a good thing, since this is the job of the operating system. That Windows and OSX have crappy/nonexisting package managers does not mean every language should roll its own.

If the police in your city are not doing their job, you shouldn't resort to vigilantism, you should stage a protest. Ideally.

Are you aware how many OSs are out there?
Package management is the job of the operating system, but this statement doesn't make much sense for go because go binaries are statically linked to go packages. So using an OS-provided version of crypto/tls or net/http isn't really an option.

Go dependencies are basically a build-time thing.

(cgo is an exception)

> which means a lot of copy and paste

Again, I don't think Go is perfect but on my list of wants, generics are not in the top 5. Can you qualify "a lot" in a real project you've worked on? Because after writing a good chunk (over 50k lines) of Go code, I haven't felt the sting as much as I hear it complained about.

> the lack of idiomatic way to deal with dependencies(no defacto package manager

Again, is this really a big deal? There's plenty of options, and if you are shipping any-type of commercial product you are going to want to be vendoring your dependencies in-house anyway. In which case, depending on something like NPM/remote maven repos is not a viable options anyway.

> Again, I don't think Go is perfect but on my list of wants, generics are not in the top 5.

Would you mind sharing your top 5 wants? I'm interested.

Sure! In order:

A Debugger.

Better IDE options.

Binary sizes small enough to use for embedded programming.

Pauseless Garbage Collector.

Less awkward variable declaration.

> A Debugger (some limitations IIRC) (a work in progress, but promising)

I documented a real-life experience here:

Read the requirement, elaborate a little more by me in some of the comments, and see how the combinations I had to deal with quickly multiplied to cause high tedium.

All the for loops and array indexing you do in place of simple map / filter / reduce calls would count in my definition of copy and pasted code.
I was a bit surprised by the length. Not a huge difference, but one of the best things about the K&R book was how short it was. But, I too have been been curious to look into Go. This might be the excuse I needed.
I'd say any length increase would be justified, Go does have a pretty large standard library...
YES. I read and re-read the original K&R (The C Programming Language) book many times as a child. It's one of my favorite tech books ever written: clear, concise, challenging, useful.

I've recently started writing more and more code in Go, for simple performance reasons, and it'd be amazingly great to relive the K&R wonders of my childhood with a new language =)

Just pre-ordered a copy, can't wait.

I look forward to the time when Go adds generics and all the people who told me that you don't need generics in Go start telling me how awesome and super-duper useful generics are.
I haven't heard anyone, including the go authors, say that generics are bad and you absolutely don't need them in Go.

Personally I like Go a lot and don't miss generics much, but for some things I'd love to use generics some day. It's basically about trade-offs eventually. To quote the FAQ about it:

> enerics may well be added at some point. We don't feel an urgency for them, although we understand some programmers do.

> Generics are convenient but they come at a cost in complexity in the type system and run-time. We haven't yet found a design that gives value proportionate to the complexity, although we continue to think about it.

I predict that there will be some kind of support for generics... eventually. Not explicitly in the language itself, but some added 'go generate' style tooling support. You will be able to define containers and such to use the empty interface, and add in some comments saying you want a version for strings, or floats. And the generate step will run to create the type-specific versions, which will then be compiled as usual.

There's definitely work to be done in the details.

This is my general read on where I think the community and developers are going... that's all.

As far as I recall, the apologists don't say generics are bad - but rather, not necessary (at times conceding they are useful). Which sounds reasonable to me.

Who needs generics? 'Need' in it's dictionary sense. i.e. is there an algorithm you can't write in a language because the language lacks generics? Great to have? Yes. Need? No.

Yet another Turing tarpit argument?
Here's rsc (one of the core Go dev's page) on generics.

They do believe it's a useful feature, they just don't think the tradeoffs justify it yet. (People who loudly clamor for generics tend to ignore these tradeoffs.)

I'd love if people would stop linking to something which is so obviously wrong (or at least read it before linking).

Go devs made it clear that Go won't get Generics, and it's fine.

Unfortunately, that thing is a false trichotomy. The fact is, choosing option 1 does not save you from the consequences of options 2 and 3. The reason is that the programmer now has to make a choice between boxing things manually, or implementing the same algorithm multiple times, just as the compiler would have done. So in reality there is a dichotomy: slow compiles, or slow runtimes.
Definitely some truth to this, but in practice, the fact that you have to manually do things means that you'll make decent choices -- you'll use interfaces for most stuff, and specialize the stuff that needs to be concrete, and life will be OK, if a bit clumsy.

With generics, it's easy to end up in a situation where just by instantiating some simple-seeming class, you get a whole giant pile of stuff, more than any sane programmer would create by hand.

(I wish I had it at hand, but there was an excellent post from a .NET/CLR guy a while back that went into all the crazy stuff that got instantiated just by creating one specialization of List<T>, the associated performance overheads, and the things the compiler and runtime tried to do to avoid those.)

That bad? Wow. I would love to read that.
You should, however, note that Go does not have inheritance. That single difference reduces the `crazy stuff' by an order of magnitude. In addition, not having inheritance also means that you do not need to take variance into account, which further reduces the complexity significantly.
Awesome. For those who don't know, Kernighan is the "k" in "awk" :)
Also the "K" in "K&R"
Also, the K in Kernighan Lin (Graph min cut) and the Lin-Kernighan heuristic (Traveling salesman)
It's Brian Kernighan, enough said. I am sold.
I actually have to say I wasn't familiar with this author having never spent time in C. After some Googling I'm excited to see he's fellow Canadian and looks to be a pioneer in computing as well. It also seems he's worked with Rob Pike, another fellow Canadian :)
Good news! I think Go is the best alternative between C speed and simplicity of Python!
320 pages vs. 274 for the 2nd edition of The C Programming Language. Not bad, considering how much more "stuff" Go has in it vs. K&R C.
Anyone know if Kernighan has written a lot of Go code himself, or is he onboard more for his technical writing skills?

(There's the Bell Labs connection of course)

He and Rob Pike have written a few books together, that's likely the main connection.

I follow the Go community fairly closely and hadn't heard of Kernighan in connection with Go, but he may also not be advertising his use of it.

kernighan also wrote the tutorial on the Limbo programming language:

he's obviously good at it, and the perspective of someone not involved with the creation of the language is a bonus.

He authored the first 4 commits in the Go repository ;)

Kernighan is one of the core authors of the language. So I'd say it's for more than just his technical writing skills.
You're mixing up the Bell Labs / Unix greybeards.

- Ken Thompson: Bell Labs, B, Unix, Plan 9, Go

- Dennis Ritchie: Bell Labs, C, Unix

- Rob Pike: Bell Labs, Unix contributor, Plan 9, Limbo, Go

- Brian W. Kernighan: Bell Labs, Unix contributor, AWK, AMPL


- "The C Programming Language" - Kernighan & Richie

- "The AWK Programming Language" - Kernighan & Aho

- "The Elements of Programming Style" - Kernighan & Plauger

- "The Unix Programming Environment" - Kernighan & Pike

- "The Practice of Programming" - Kernighan & Pike

- "The Go Programming Language" - Kernighan & Donovan

The main authors are Ken Thompson, Rob Pike and Robert Griesemer, Kernighan knows Ken since the 70s and Rob knows both of them since the 80s.
No he isn't. Thompson gets slighted the same way by everyone thinking K&R _created_ C, when that was T&R.

They may all be greybeards but they are in fact distinct people!

I spoke to Kernighan about it a few days ago, and he seemed to be doing a good amount of go development.
That's really a good news. "The C Programming Language" is one of my favourite book. This should the next one!
"Good Programming is not learned from generalities, but by seeing how significant programs can be made clean, easy to read, easy to maintain and modify, human-engineered, efficient, and reliable, by the application of common sense and good programming practices. Careful study and imitation of good programs leads to better writing." - [1]

I'm a huge fan, have nearly everything Kernighan's been involved with, and have profited greatly from his writing. I look forward to picking up the Go book, and modernizing a bit.

[1] 'Software Tools', Brian Kernighan, P.J. Plauger, 1976

In my personal view, I find it disappointing that someone like Brian Kernighan, as a co-author of C, only got as far as Go. I would have loved it much more to see him working on a language like Rust, that actually seems to point to the future of programming languages (or does its best at it), while Go looks like a stopgap and a dead end right from the beginning.

Go seems a fine piece of engineering in so far as it directly implements Google politics & some of their technical interests, but it's of little use outside of that, despite all the hype. A pity, really.

In my personal view, I find terribly arrogant to find disappointing how far Brian Kernighan has got. Even only what he has done between C and Go is more than most successful careers.
Fair enough.
Go and Rust are allies, not enemies. Rust is a language driven by a goal, not by blind ideology, and that goal is to make the world a safer place by leveraging memory safety in a low-level context. Given that Go is also memory safe in its default configuration, any C or C++ service that is rewritten in Go still has the effect of making the world a safer place.

Programming languages are a means, not the end!

That's certainly true. I was remiss in not qualifying my statement better
That I agree.

Regardless of I and others might think about Go's design, every user application that gets written in Go instead of C or C++ (assuming C like code instead of proper safe C++14), is an improvement on the current torrent of CVE exploits.

I've had tons of fun with Go, and I've also used it in real production code!

I don't think it is really fair to say he "only" made it this far. It's something that actually brings enjoyment and productivity to possibly millions of people!

BASIC brought enjoyment and productivity to possibly millions of people. That doesn't mean there's nothing better.
That's true, but it also doesn't mean BASIC wasn't an accomplishment!
Brian is not the co-author of C, he wrote most of K&R however.
C was created by Thompson and Ritchie. The book was written by Kernighan and Ritchie. As a result Thompson's contribution is often forgotten, which is a shame.
Why... that isn't what they do. There are people more qualified that actually are working on the future.

More qualified because Kernighan isn't a programming languages researcher, what he has done and does may be great, but just because he is great in one section of computer science doesn't mean there is any reason to expect or even want him or others to venture into other sections just because.

I think this comment is awesome and makes total sense if you read it in Comic Book Guy voice.

Actually, I think Comic Book Guy voice works for so many of the comments that get downvoted on HN. There should be set of tags that mods can put around a comment to signify "relevant and humorous if read with Comic Book Guy voice", so that the community doesn't miss out on comedy gold.

OMG, I can't upvote this enough :)
Your reply seems to have gotten some downvotes (probably from people who can't take everything seriously enough), so I'm making a point of giving you the one upvote I have. I did something to deserve this reply so you shouldn't be punished for it.
Good for you. I upvoted this reply. We need more humor in the world, and someone who can take a joke deserves the upvote.
C wasn't a particularly groundbreaking or future building language either. It basically just took a bunch of well known features from some popular languages at the time and packaged them together in a way that directly made it easier for Ritchie to solve the problem he was working on at the time (developing and porting Unix).

So as such Go and C have much in common.

edit: Originally wrote Kernighan instead of Ritchie. Kernighan as far as I know had nothing to do with the design or creation of C.

FWIW, I love C for what it is. When I learned C, I came from Assembler so C felt like a perfect fit; its thin layer of abstraction wasn't too much of a learning curve and a very welcome addition to the tool chest. I just would have hoped for Go to make a “bigger” jump than C did at its time.
It has been a long time since I bought a hardcopy programming book. Alternate forms of documentation and a Safari subscription have replaced these semi-frequent purchases. And although I can't argue against the practicality and economics of this new way, it certainly evokes none of the excitement of getting the new language book home, cracking the binding, and spending the rest of the evening curled up on the couch.

Go has been my most used new language and the timing of this book is good. I'm looking forward to adding it to my (real) bookshelf.

I would like to take a glance. Does any one know where is the Table of Content? Thanks.

Seems like a no-nonsense approach like the K&R book. I am sold already :).

The book is the #1 Best Seller in Computer Programming Languages and it's not even been released yet.. wow! I'm studying their C book right now for a university class, probably going to pick this one up right after.
Thanks Dave for the link. I just pre-ordered the book :-)
for folks who don't know it (yet), here is the toc:
No Kindle edition? :-(
Considering this thing doesn't release until August 2015 I think they have plenty of time to add one.
Honest question here: Why do I need a book about Go when all the doc is living online? that just feels so 90's.
Too bad you can't buy it in a Kindle edition, I would have bought that.
All the fun of The C Programming Language with none of the K&R braces!
Am I blind, or is there only a paperback edition, no digital version?
Great, now I have to learn Go to justify getting this book!
Does anyone know if they are selling a digital version?
Considering that it's not currently for sale, there's no digital version. That said, the publisher typically has had digital versions in the past so I'd expect there to be one when it's finally available for sale.
There's a common saying that, "Everything about Go is great - except the language".

I guess a book written by Kernighan himself shows how wonderful the ecosystem is.

It's in no way "common" saying!
So when do we start calling this K&D?
Well, goodbye $40.
The K&D?
bwk, so getting this.
++, being unary, has higher precedence than &. K&C++ being K&D makes a lot more sense than (K&C)++, which I don't think will even compile, since K&C is not an lvalue.
What made Go click for me is a simple realization: it's a language made by systems people, not by PL researchers.

Everything makes sense after that. The language in isolation is boring and perhaps even anachronistic: a modern ALGOL dialect with first-class green threads.

But as many people have said, the tooling and the libraries are simply top-notch. This is unsurprising: the people behind Go all have experience with things such as Research Unix, Plan 9 and just infrastructure in general. They've been instrumental in shaping up the lower level workings of our present systems, so they're intimately aware of those aspects. 9P, Acme, rio, the Acid debugger, the Plan 9 compiler collection... among other tools, reflect that their brilliance is in engineering rather than science.

But more importantly: these people are experts in managing complexity and integrating things. Thus, in isolation, Go's components look bland and uninteresting. Cumulatively, they form a unique experience. Hence why Go has such a strong culture of "pragmatism" that a lot of PL geeks scoff at.

So I've pretty much stopped thinking of Go the language, but rather Go the toolchain.

Mar 03, 2015 · 12 points, 1 comments · submitted by d3141
Purchased. Even though I know Go already, I feel like throwing money at Kernighan and Donovan. Most of my career rests on an early reading of K&R.
HN Books is an independent project and is not operated by Y Combinator or
~ yaj@
;laksdfhjdhksalkfj more things ~ Privacy Policy ~
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.