
Why I Like Go - craigkerstiens
https://gist.github.com/freeformz/4746274
======
graue
These points are all very true, and I admit I haven't done more with Go yet
than play around. But there are a few reasons I feel I _don't_ like Go, or at
least, there are warts that will probably limit how much I'm going to like it.

Nil pointers are #1 on that list. Tony Hoare called them a "billion dollar
mistake"[1]. In Go, as in C, C++, or Java, any pointer can be `nil` (similar
to `NULL`) at any point in time. You essentially always have to check; you're
constantly just one pointer dereference away from blowing up the program.
Since ways of solving this problem are known, I find this hard to swallow in a
new language.

Compare Rust where, unless you have explicitly used the unsafe features of the
language, all pointers are guaranteed non-nil and valid. Instead of a function
returning a nil pointer, it returns an `Option` type which is either `Some
ptr` or `None`. The type system guarantees you have considered both
possibilities so there's no such thing as a runtime null pointer dereference.
Scala has a similar `Option` type, as does Haskell, calling it `Maybe`. In
2013 I don't want to still constantly check for a nil pointer, or have my
program blow up at runtime if I forget.

The second disappointment is that when I looked into it, it seemed there are
ways to call C functions from Go code, but no working way to call Go from C
code. Maybe that wasn't a goal at Google, but it seems like a missed
opportunity. As a result, you can't use Go to write an Nginx module, or an
audio plugin for a C/C++ host app, or a library that can be used from multiple
languages.

I think there is a real unmet need for a higher-level, safer language you can
use to write libraries. Imagine if zlib, or libpng, or the reference
implementations of codecs (Vorbis, Opus, VP8) could be written in something
like Go. Or spelling correction libraries. Currently we have two tiers of
libraries: those written in C/C++, which can be used from any language under
the sun (Python bindings, Ruby bindings, Perl bindings, PHP bindings...), and
those written in high-level dynamic languages (Python, Ruby, Perl, PHP, ...)
which can _only_ be used by the same language. We need a middle ground. C
isn't expressive or safe enough to deserve to be the lingua franca like this.
And Go is tantalizingly close to replacing it, but not quite.

[1]:
[http://qconlondon.com/london-2009/presentation/Null+Referenc...](http://qconlondon.com/london-2009/presentation/Null+References:+The+Billion+Dollar+Mistake)

~~~
dscrd
"Compare Rust where, unless you have explicitly used the unsafe features of
the language, all pointers are guaranteed non-nil and valid. Instead of a
function returning a nil pointer, it returns an `Option` type which is either
`Some ptr` or `None`. The type system guarantees you have considered both
possibilities so there's no such thing as a runtime null pointer dereference.
Scala has a similar `Option` type, as does Haskell, calling it `Maybe`. In
2013 I don't want to still constantly check for a nil pointer, or have my
program blow up at runtime if I forget."

So how is nil checking different from when I write a function that pattern
matches against a Maybe in a way that I only match against the "Just" case?

~~~
bad_user
We have been using Scala lately for a couple of web services that are now
running in production at our startup.

The difference is huge, because Option[T] references are type-checked at
compile-time. Whenever a reference can be either Some(value) or None, then you
are made aware of it and you are also forced to either handle it (by giving a
default value, or throwing a better documented exception) or you can simply
pass the value along as is and make it somebody else's problem.

Option[T] in Scala is also a monadic type, as it implements filter(), map()
and flatMap(). It's really easy and effective to work with Option[T]. In
comparison with "null", which isn't a value that you can work with other than
doing equality tests, None on the other hand is an empty container for which
you know at compile-time the type of the value it should contain and in Scala
it's also an object that knows how to do filter(), map() and flatMap().

My code is basically free of NullPointerExceptions. This doesn't mean that
certain errors can't still be triggered by null pointers, but those errors are
better documented. What's better? A NullPointerException or a
ConfigSettingMissing("db.url")?

Of course, to tell you the truth, Option[T] (or Maybe as it is named in
Haskell) is only really useful in a static language. In a dynamic language,
such as Clojure, especially if you have multi-methods or something similar,
well in such a case Option[T] is less useful. And before you ask, no, Go is
not dynamic and people saying that Go feels like a dynamic language, don't
really know what they are talking about.

~~~
blablabla123
>My code is basically free of NullPointerExceptions. This doesn't mean that
certain errors can't still be triggered by null pointers, but those errors are
better documented. What's better? A NullPointerException or a
ConfigSettingMissing("db.url")?

Almost always it is a matter of 2 seconds to find the source of a nil pointer
error. Given that I would almost never forward raw error messages to the user,
I cannot really see a gain.

However having a language that combines this Scala feature with Go's
exception-free error handling, would be awesome and a true solution that would
make software run more reliable and with less crashes.

~~~
bad_user
> _Almost always it is a matter of 2 seconds to find the source of a nil
> pointer error_

Either you're some kind of a super-human, or your code bases are really tiny.
Yes, you usually can figure out the trigger of a null pointer exception, but
not the _source_ that made it happen and with complex software the stack-trace
can get a mile long ;-)

The biggest problem with null pointer exceptions is precisely that (1) they
get triggered too late in the lifecycle of an app, (2) such errors are
unexpected, non-recoverable and sometimes completely untraceable and (3) you
need all the help you can get in tracking and fixing it.

Either way, throwing better exceptions is just one of the side-effects of
using Option[T], because in 99% of the cases you end up with code that
functions properly without throwing or catching exceptions at all. And you
completely missed my point focusing only on a small part of it that's also the
most insignificant benefit of Option/Maybe.

> _However having a language that combines this Scala feature with Go's
> exception-free error handling_

First of all it's not a Scala specific feature, as the Maybe/Option type has
been used and is proven from other languages, such as Haskell and ML. That the
Go language creators took no inspiration from these languages is unfortunate.

Also, people bitching about Exceptions have yet to give us a more reliable way
of dealing with runtime errors. The only thing that comes closest to an
alternative is Erlang and yet again, the Go language designers took no
inspiration from it.

~~~
smosher
Lately, the biggest complaints about PL design seem to be that they didn't
take enough inspiration from ML-family or Erlang.

~~~
masklinn
For Go? The biggest complaints about PL design are and have always been that
its designers ignored or discarded the previous 30 years of PL (theoretical
and practical both) when creating it.

~~~
smosher
Not just Go. But in Go a lot of problems could be solved by doing things the
Erlang or ML way... then there's the new problems they've invented, like
enforcing things that don't matter instead of things that do.

~~~
blablabla123
>then there's the new problems they've invented, like enforcing things that
don't matter instead of things that do.

Never heard such complaints from users that have used it for a few months. I
assume you are talking about unused imports and variables. Actually it helps a
lot because it keeps your code clean and clear.

------
jxcole
I would like to add one other thing I like about go: There is a parser and an
abstract syntax tree in the standard library.

Sometimes when I'm programming at work I need to add log messages to every
method on a large interface (or several interfaces). It is obvious to me that
there needs to be some tool or library that adds these very simple log
messages to these methods for me (like "Entering method getUser(UserId=2701,
SessionId='AABCF')").

The tool we have at work uses runtime generated code to add these messages to
methods automatically. Besides the performance hit this is fine, except for
one problem. Sometimes it doesn't work; and it is impossible to figure out
why. You turn on the tool, add all the right metadata, and nothing happens.
You could argue that it is a tool problem, but I think one of the big things
is that runtime generated code is just vastly inferior to compile time
generated code.

If I were using go, my tool would open the code, read the interfaces, and spit
out a nice implementation of logging in a .generated.go file and if it doesn't
work for some reason I can actually go look at the generated code and see why.
Trying to figure out why an implementation isn't working by looking at it's
dynamically generated bytecode or .net clr is not fun at all.

~~~
contingencies
_runtime generated code is just vastly inferior to compile time generated
code_

That's a big call. I think you should curtail it, eg. "runtime generate code
can be harder to debug". This is often true but not always. Let's not get in
to workmen and their tools.

~~~
lemming
I agree with the GP's statement, because "harder to debug" == "vastly
inferior". In my last job we worked a huge amount with generated code, and
having generated source that you can step through is essential. I've never
seen runtime generated code that's easy to debug.

~~~
contingencies
Your logic seems to be that because some runtime code can be harder to debug (
_This is often true but not always_ ), having personally encountered such, you
therefore declare that all runtime code is vastly inferior. Sorry, but this is
ridiculous. Can you contribute something more solid than an anecdote?

~~~
lemming
I'm sorry you think it's ridiculous but it's just my opinion, after all. Feel
free to ignore it. Can you give us an example of runtime generated code that
is easy to debug?

~~~
contingencies
I can't. However, I do believe that software development _in general_ is
headed away from monolithic compilation, and that future systems will be
largely real time, parallel, multi-component, perhaps more heterogeneous, and
almost certainly predominantly interpreted.

Our habits trap us in to seeing things one way.

------
rogerbinns
I'm still of the opinion go messed up the error handling badly. As a simple
example note how every tutorial doesn't bother looking for the error return of
println calls and hence would silently ignore errors.

IMHO the ideal solution is that if you make no effort to look at the error
return of a function, it is automatically returned to your parent. This is
somewhat analogous to exceptions, but they require a lot more syntax. (Yes I
know about panic/recover.)

~~~
drivebyacct2
I always find it _interesting_ that people repeat the example of println as if
it's any different than any other time that you make a decision to ignore or
check error codes. It's no different than most other languages that would be
in Go's category.

Also, I presume you meant fmt.Println (println shouldn't be used and almost
surely doesn't return an error).

>is that if you make no effort to look at the error return of a function, it
is automatically returned to your parent

That would be... very, very, very strange for a huge number of reasons.
Syntactically, function signature wise... You're basically just asking for
exceptions in that case. And besides, that's how most functions that can error
work, as I'm sure you know from any example code.

    
    
        function makeSomething() (Something, error) {
            something = new(Something)
            err = mightBreak(something)
            if err != nil {
                return nil, err
            } else {
                return something, nil
            }
        }
    

Yes, it's explicit error handling. Yes, it's griped about on _every_ ,
_single_ HN thread about Go. And the mailing list, extensively.

For a parallel example, do you call checkError() on your PrintStream
(System.out) in Java after calling System.out.println? If not, you're not
_really_ checking to make sure println worked:
[http://docs.oracle.com/javase/6/docs/api/java/io/PrintStream...](http://docs.oracle.com/javase/6/docs/api/java/io/PrintStream.html)

~~~
sbov
Make a decision to or _forget to_ check error codes.

My gripe is fairly different from the OP's in this aspect. Go is inconsistent.
For functions that return values I need to use, I will be warned by the
compiler if I forget to handle the error. For those that don't, the compiler
will happily let me accidentally ignore the error.

I'd rather require that all return values be handled whether I use them or
not. For the rare case that a function returns a value I honestly don't care
about, I can just use _. At least I'm not hiding the fact that I knowingly am
ignoring stuff.

(Edit: despite the above, I still do enjoy using Go.)

~~~
drivebyacct2
I can understand why that inconsistency is frustrating. Similarly:

    
    
        typedObj, err = something.(type)
        typedObj = something.(type)
        obj = someMap[key]
        obj, ok = someMap[key]

~~~
zeeboo
It's

    
    
        typedObj, ok = something.(type)
    

just like it is with maps, or any other ", ok" thing.

<http://play.golang.org/p/I-5kD88knC>

~~~
drivebyacct2
Oi vey, mea culpa.

------
shurcooL
I've become aware of Go just a few months go, but I already like it so much
that I'm planning to make my next/current project in it, after using C++
exclusively the last 8+ years.

It has a lot of good things going for it, as a modern language should, but IMO
that only makes it a viable alternative.

What really pushes it over onto the "I wanna use it" side is how easy and
natural it makes concurrent programming. See e.g. vimeo.com/53221560

------
blt
It's interesting how many people post about moving to Go from an interpreted
or VM language background. The original presentation video pitched it as a C++
replacement, but that is clearly not the whole story. This author does not
seem to have much experience in native development. I wonder if the Go
designers predicted how many people they'd convert from python/ruby/java.

~~~
kbuck
Frankly, I think a lot of the people currently working with C/C++ are avoiding
Go because of the garbage collector. You can't trust a garbage collector; you
don't know when it will run, how long it'll take, or how quickly it will free
the memory you used. C/C++ programmers are used to having complete control
over all of this. Sure, you could familiarize yourself with the internals of
whichever GC you're working with, but at that point you might as well have
invested the same amount of time writing the program in a language without a
GC.

~~~
jff
I'm going to make the argument that a lot, if not the majority, of C/C++
programmers don't _need_ complete control over memory management. I think in
many cases (not OS, not real-time), saying "but I need absolute control over
memory management so I can optimize!" is the equivalent of "I write everything
in hand-coded assembly because it's more efficient". It's probably not, the
machine can probably handle it better, and you're missing out on useful
functionality. You know what happens when I allocate and free memory myself? I
generally end up with either a leak or a double-free, and I doubt I'm such a
terrible programmer that I'm the only one like that.

~~~
p0nce
False dichotomy. If you use RAII, exceptions, and smart pointers in C++ there
will be no leaks, no double-free, and not even a need for a GC. I know it is
difficult to make a point on the Internet, but resource leaks really are a
solved problem in C++.

~~~
jff
Yes, but then you're stuck using C++, RAII, and exceptions. Let's not even get
into which smart pointer you should use--a Googler I know has recounted
stories of massive internal mailing list arguments over exactly which of the
half-dozen smart pointer implementations they should be using.

~~~
p0nce
So, because C++ has imaginary problems, we should all switch to a language
that solve them, while being worse at all other things that matters (you know,
like code generation)?

------
jetti
"Oh, and there isn't any pointer math, so you won't screw yourself with it."

It has been said before and I'll say it again here, but because you can mess
stuff up because you don't know what your doing is a terrible reason to not
have something in a language (or even a program).

~~~
ericbb
Incidentally, I don't think it's entirely true that "there isn't any pointer
math". I've never used it but I understand that you can do C-like pointer
tricks by using the package called "unsafe": <http://golang.org/pkg/unsafe/>
and <http://golang.org/ref/spec#Package_unsafe>

~~~
dchest
Yes, indeed. Here's the "canonical" C strlen translated to unsafe Go with
pointer arithmetic:

    
    
      package main
      
      import (
      	"fmt"
      	"unsafe"
      )
      
      func strlen(b []byte) int {
      	str := uintptr(unsafe.Pointer(&b[0]))
      	s := str
      	for ; *(*byte)(unsafe.Pointer(s)) != 0; s++ {}
      	return int(s - str)
      }
      
      func main() {
      	fmt.Println(strlen([]byte("ho ho ho\000")))
      }
    
    

Not that anyone should use it :-)

The safe and readable variant of this, often used in Go code, is "slice
arithmetic", like this:
<http://golang.org/src/pkg/crypto/sha256/sha256.go#L105>

------
jsdavo
It gets Damien Katz's approval so I'm learning it ASAP.

<https://twitter.com/damienkatz/status/289575389641179137>

------
dinkumthinkum
These posts make me feel like Go is some oddball quirky person we all know and
we all feel like we have talk about how great he/she is at some drunken party.
I mean, we all love Go and all ...

~~~
pjmlp
Some people need support from others to confirm they are making a good choice.

------
flashmob
Another great thing:

gofmt - Go has no style guide, just this tool!

Committed code ends up looking cleaner and you don't have to adapt to other's
wacky standards. No more tabs vs spaces arguments or where to place that
brace... brilliant.

<http://golang.org/doc/effective_go.html#formatting>

~~~
jff
It does have a style guide, it's just that gofmt will automatically make your
code conform to that style guide :)

The Go style is close enough to my normal C style that I end up mostly
conforming anyway, but gofmt is great for making code look a bit prettier.

------
wsc981
Unrelated: I like the fact this person used Github as a "blog". I've been
looking for some good blogging software & host for a while, but Github might
just fit my needs :)

~~~
minhajuddin
Checkout <http://substancehq.com> too, it is a very simple hosted blogging
engine.

~~~
wsc981
Thanks, it seems like a nice tool. Formats Objective-C as well! Great for my
purposes :)

------
Daviey
Argh! I felt rage reading: Package System or lack there of. Since Go compiles
everything statically, you don't have to worry about packages at runtime. But
how do you include libraries into your code? Simply by importing them via url,
like so: import "github.com/bmizerany/pq"

It was all good until that point.

~~~
burntsushi
Are you going to say why, or just let us guess?

~~~
lobster_johnson
My guess: Remote packages are useless because (afaik) you can't specify a
revision. This means "go get" will get the latest HEAD, which could be
anything.

Go needs something like Ruby's Bundler to let a package declare what versions
are required and let you pin to specific versions.

~~~
burntsushi
If I desperately needed a specific version of a package, I'd fork the project
and freeze it where appropriate.

Does the `go` tool _need_ to be aware of versions? IMO, no. Would it be a nice
feature if it could be added without making the tool difficult to use? Yes.

But so far, it hasn't appeared to slow anyone down. I've worked quite a bit
with distribution tools for both Python and Haskell, and Go's tool is a breath
of fresh air.

------
mvzink
Question re: only utilizing one CPU and GOMAXPROCS: would it be in bad taste
to, by default, for a program which might be used by other people (and uses
goroutines extensively) to include in initialization
"runtime.GOMAXPROCS(runtime.NumCPU())"?

~~~
wmf
C or Java programs use all cores by default. I think it's reasonable for Go to
have the same default.

~~~
jlgreco
C, previous to C11, didn't even have a concept of threading...

(And who the hell is using C11 like that anyway?)

~~~
wmf
OK, pthreads.

~~~
jlgreco
It is going to be a pretty hard sell that mimicking pthreads is ever a good
idea...

Regardless, considering the casual nature of goroutines and the deliberate
heavy-weight nature of pthreads, I find it hard to see pthreads as being _any_
sort of argument about what Go should do, regardless of pthreads'
shortcomings. They are wildly different animals.

------
seivan
I've been thinking of leaving Ruby for web applications. Both Go and Haskell
are contenders because of the compilation step.

Been doing iOS so much lately (almost 3 years now) over the course, I've come
to love compiled languages much more.

I still use Ruby for backend services and smaller scripts. But I want to leave
it for larger backend software.

This was a nice list, thank you.

------
cincinnatus
Sounds like a list of C# benefits. In 2004.

~~~
jkat
Except for the goroutine and channel, and the type system, and the package
system.

~~~
pjmlp
Ah you mean Task Parallel Library and NuGet?

~~~
jkat
I didn't realize NuGet let you do remote path import. Nor that it was around
in 2004. Nor that it's part of the C# language spec.

Goroutine + Channels are vastly different than the TPL. The comparison is so
far off that I can't even come up with a clever analogy. There's more to
concurrency than threads, and more to communication than locks.

~~~
pjmlp
> I didn't realize NuGet let you do remote path import. Nor that it was around
> in 2004. Nor that it's part of the C# language spec.

Fare enough if you want to limit yourself to 2004 and compiler specific
support.

> Goroutine + Channels are vastly different than the TPL

If you take out your Go coloured glasses and read in what TPL does, you will
see that what Goroutines and channels are indeed available as Tasks and
Queues.

~~~
balakk
I don't know enough about Go, but Goroutines and Channels sound quite similar
to F# agents and mailboxprocessor concepts, which as I understand is not quite
the same as TPL. The former tackles concurrency, while the latter is about
parallelism. C# 5 is getting there with async/await concepts I guess.

Here's a dining philosophers implementation in F# and Go (among other
languages)

<http://rosettacode.org/wiki/Dining_philosophers>

------
z3phyr
But I like Haskell more.

------
niggler
"Go compiles down to native code and it does it fast. Usually in just a few
seconds."

Very strange statement. Most programming languages/runtimes do small
operations very quickly.

~~~
StavrosK
What do you mean? He means that you can compile a pretty large program in
seconds, most languages' compilers aren't that fast.

~~~
laureny
> most languages' compilers aren't that fast

All mainstream languages compile in about that ballpark, if not faster.

I've always found it odd that one of the driving design principles of Go was
"fast compilation". It's always struck me as odd and short-sighted, obviously
motivated by the Go authors' history with C++. If only they had spent some
more time studying other languages, they would have realized that compilation
times are really not a concern in languages these days, and they might also
have designed Go with more modern features in mind, such as exceptions and
generics.

~~~
DeepDuh
Not really a concern? I don't agree. Look at large C++ projects, and let's not
speak about GPU frameworks like CUDA, OpenCL and OpenACC. If it weren't be a
concern, software companies wouldn't invest in clusters just for compilation.

~~~
pjmlp
Contrary to what many young developers may think, C and C++ aren't the only
languages with compilation to native code.

Already in 1987 Turbo Pascal 4.0 was compiling quite fast, Borland states
around 34,000 lines/minute for the 5.5 version in 1989.

Similar compilation speeds are possible for languages with modules, since the
early 80's.

Go's compilation speed is only news for someone that never used a module based
language for systems programming like Modula-2 or Turbo Pascal, just to name
two.

~~~
stesch
It doesn't matter if somebody knows Turbo Pascal 4.0 or Modula 2 if you can't
use it.

We are repeating history because the old ways were forgotten or replaced.

~~~
ufo
What he was trying to say is that you shouldn't "design for fast compilation".
You should design the language to allow modularity and fast compilation will
naturally follow.

------
ungerik
Another one in a long list :) The case for Go:
<https://gist.github.com/ungerik/3731476>

------
grn
I remember that Go had some issues related to the garbage collector on 32-bit
machines. Are they solved now?

~~~
freeformz
Not fully... <http://code.google.com/p/go/issues/detail?id=909>

------
cwarrior
Is Go used any where else besides at Google?

~~~
freeformz
yes

------
nogo
Google pr is doing a great job with the go language. Every day 2-3 stories is
always highly rated on a language not many people outside google cares about.
Time to hellban som accounts maybe?

~~~
vanderZwan
Says an account called "nogo" created 5 minutes before posting?

~~~
drivebyacct2
Ironically there is someone creating new accounts and trolling each of the Go
posts. Last time it was someone spewing inconsistent lies about the Go build
system.

~~~
jlgreco
My money is on the 0xABADC0DA doing it. An obsession with Google's
relationship with Go and thinking that google employees were gaming HN to push
Go was kind of his MO. Really quite obnoxious, I don't know who he thought his
audience was.

------
revelation
_Simple C Interface

By using build directives you can integrade with C libraries really easily._

And its a bunch of magic. I thought these people were serious about having a
language for "systems programming".

What good is it if it can't properly interface with the systems programming
language that people actually use, C?

It seems they wanted to add "C interop", but didn't understand what that
means.. at all. You give it a header with function prototypes, because thats
apparently the only way to tell it "I want to call this native function", and
you get... undefined references for the native functions? What the hell is it
even trying to do? You don't have source and you don't have linker stubs for
_a lot_ of the libraries you want to interop with.

It's a complete non-starter. It's interop for awesome magic demos.

~~~
shadowmint
What?

CGO is pretty cool actually. It does have some irritating downsides (pkg-
config for example, is used, and there's no other option to link to a specific
library afaik)...

...but seriously, what are you even talking about?

All you need is a header, and a binary (library; .so or .dll). Done.

How would you even use a library that doesn't have a header?

Sounds like you've spent some time using COM objects and the . autocomplete
function on them; that's just windows crazy-talk, if you want to use that kind
of nonsense, go write powershell.

