

Go Is Unapologetically Flawed, Here’s Why We Use It - tylertreat
http://bravenewgeek.com/go-is-unapologetically-flawed-heres-why-we-use-it/

======
mike_hearn
The comments about Java are wrong. There's an HTTP server in the standard
library (under com.sun). It's not well known but it's there and the
documentation is quite reasonable. The API is very simple. I've used it a few
times and whilst I wouldn't run a major website on it, it's fine for smaller
tasks.

From Java 7 onwards files can be read with a single method call. Look at the
static methods on the Files class.

I find the article to be poor. He says he likes Go, and then proceeds to
illustrate why nearly all the features of it are dubious. Then he admits that
any article that criticises Go had to be prefixed with his disclaimer because
otherwise the community will get nasty, so does he really like Go? Hard to
say. His employer requires him to use it so it's not like he can openly say he
hates it.

Finally he says Java is ghastly, but his only evidence for this is he doesn't
like one of the frameworks built on it ... a framework that Go has no
equivalent to anyway. Ok... so don't use j2ee then. Use something like Play or
Ninja. He would then benefit from good GC and working debuggers/CPU profilers.

~~~
otis_inf
Agreed, I also didn't understand the real point the author was trying to make:
if you hate it, say so and be done with it, don't wrap it in a 'I love you to
death but..' kind of way.

I think with 'go' as a language when you start with it, there's a lot to love:
things are simple again; "Look ma, a real program that does something with
almost no code and also no magic shit behind the scenes!". But things are
always simple and nice in the beginning, when you are focusing on just a small
part of the complete picture.

The problem with 'simple' is that unless it abstracts away all complexity
you'll ever need to deal with, you'll need to do a lot of work yourself: it's
the typical RISC/CISC argument from yesteryear: do you want a small
instruction set which is simple but results in a longer program, or a complex
large instruction set which results in a smaller program?

So, to be able to deal with all possible complexity in all possible scenarios,
either the language has to be vast in its expressiveness (go isn't) or it has
to come with a vast standard library which offers additional expressiveness
through classes / methods / functions / subsystems or whatever the language is
lacking, OR you have to write it all yourself.

In the end, the net-result is the same: the system as the end result of your
work is the combined complexity of the code written by the developer(s) and
the complexity of the libraries used. Go doesn't change that, it just moves
the divider between 'own code' and 'libraries' more towards 'own code', even
if that's simpler to write because the language lacks things which some people
might consider 'oh god this is complex, I'll never understand this'.

------
breakingcups
I like Go, but I agree with most said in this article.

One nitpick about his comment about sending to closed channels. This is indeed
programmer error and SHOULD panic, in my opinion. It is clear the author has
not read up on the semantics of channels. Channels should only be closed by
the sender. If you have multiple senders, how on earth would it be a valid
situation for one of these senders to close the channel if the other sender
still has data to send? You're going to need some form of synchronisation
mechanism for this.

~~~
jusssi
I believe the idiomatic way to solve multiple writers would be to give each
writer it's own channel, and multiplex the output of those to a single
channel. The problem is, without generics you need to create a new multiplexer
for every type of channel payload.

Also, if semantics make life complicated, they should be changed. Since
there's already an 'ok' return flag for channel receive, I have hard time
understanding why there can't be one for channel send.

~~~
tshannon
Yeah, I've found the simplest way to have multiple writers / readers is a
mutex.

I was suprised to read that they actually consider removing the sync/atomic
packages. It's crucial in my opinion, and would complicate a lot of code if
had to be written with channels.

------
4ydx
Summary: No generics. No versioning. The author said they wanted to bring more
to the conversation, but it seems that they really didn't after all.

~~~
lsiebert
Also using straight mutexes are faster then channels, and many parts of the
standard library use them because of this.

------
ngrilly
_A copy of the comment I posted on the author’s blog_

I agree that generics are very useful when writing reusable libraries, but I
disagree they are absolutely necessary when writing and maintaining software
at large scale. At large scale, at some point, processes communicate with
other processes on the same machine or over the network, and you have to
marshal/unmarshal and type check at runtime.

Your example with the function isInt64InSlice is a good illustration of why
the lack of generics is annoying at small scale, but it hardly shows why this
is a problem at large scale.

PostgreSQL is an example of a complex piece of software, written in C, which
doesn't use generics and is still very readable and maintainable.

A few other technical points:

\- "Cannot add methods to types from a different package": Would you want
something like extension methods in C#?

\- "Channels are slow": I've read there is some work going on to improve them.
That said, you admit yourself that Go is still one the best option among the
"concurrent" languages. Are you aware of another language with a similar
mechanism builtin in the language or the library and that performs better on
this matter?

\- "Accidental implementation of an interface": I agree this a problem in
theory, but in practice it's very rarely an issue. Have you been beaten by
that often? Do you think the benefits of implicit implementation are not worth
it?

\- "Cannot implement your own exceptions": Yes you can. You can pass some
value to panic and retrieve it upper in the call stack with recover and decide
what to do depending on the value. It's not something Go developers do often,
but there is some use of this technique in the standard library for example.
It's explained in "Effective Go".

\- "Map returns a bool instead of an error": I don't see the issue here. A lot
of other languages do the same and return a default value and/or a boolean at
false when you probe a map with a missing value.

\- "Adding an item to a closed channel panics": This is a programming error,
like a division by zero or an out of bounds array access.

\- "Channels as iterators": Goroutines and channels are not designed to build
iterators. They offer a general low-level mechanism for concurrency. How would
you expect the goroutine to know that nobody is listening anymore and
shutdown?

About the community, I would not call it "stubborn". In my experience, it is
generally helpful and very professional. But I agree that the topic of
generics has become a taboo, which I regret. It looks like the core team wants
to focus on improving the compiler, the runtime, the library, the tooling and
the garbage collector, and because of that wants to keep the language stable
in the meantime. I understand the frustration, but don't you think their
decision makes sense and is the best way to use the limited resources of the
core team?

You wrote that "a language can have considerable depth while still retaining
its simplicity". What languages would you recommend that solve the flaws of Go
while preserving its simplicity (in terms of user experience)? It's a sincere
question. I'd like to use such a language.

More generally, you ask how can we make developers more productive and how can
we enable them to solve problems? That's interesting because this is precisely
the question Go tries to answer. Are you sure the answer lies in a more
powerful programming language? What about the runtime, the tooling, the
libraries?

The Go team thinks the answer lies in simplicity (light syntax, garbage
collection, interfaces, composition over inheritance, builtin
arrays/slices/maps), builtin concurrency (goroutines, channels), great tooling
(speed of compilation, go test, gofmt, godoc), easy deployment (no virtual
machine, static binary).

Do you think the answer lies in having type parametricity, algebraic data
types, pattern matching, immutability, Hindley-Milner type inference, higher
kinder types, etc.? I'm not saying they are not useful or desirable. I'm just
saying that the low hanging fruits in terms of developer productivity may be
elsewhere.

