Hacker News new | ask | show | jobs
by richbell 951 days ago
> True, and because of this...

This is a false dichotomy. One does not imply the other.

Go is also not a simple language. It is deceptively difficult with _many_ footguns that could have easily been avoided had it not ignored decades of basic programming language design.

Many things also aren't straightforward or intuitive. For instance, this great list of issues for beginners: http://golang50shad.es/

2 comments

I'm sorry but nearly all of them are along the lines of "I came from language X and in X we did it this way, but Go's syntax is different". That's not a footgun.

You know what's a footgun? Uncaught exceptions popping up in places far away from where they were created at which point you have very little context to deal with it robustly. Use after frees. FactoryFactoryFactories.

I don’t have too much an opinion on either side here, but as a developer who works full time in Go (and has for >6 years) all these things exist in Go.

Uncaught exceptions -> panics, like what this nil catcher is aiming to solve

Places far away -> easy goroutine creation with no origin tracking makes errors appear sometimes very far away from source

Use after free -> close after close

FactoryFactoryFactories -> loads of BuilderFunc.WithSomething

Lots of other pains I could add that are genuinely novel to Go also, but funny that for everything you mentioned my head went “yep, just called X”

> I'm sorry but nearly all of them are along the lines of "I came from language X and in X we did it this way, but Go's syntax is different". That's not a footgun.

You're right, I meant to link that in reference to how Go can be difficult to learn despite how it simple it seems. Not sure how I a sentence.

The overview of that site explains its purpose/necessity quite well. Some things are footguns, many are just confusing time-wasters. Nevertheless, they are frustrating and hamper the learning process.

> Nevertheless, they are frustrating and hamper the learning process

But that is the learning process. What else is there to learn in a language if the syntax doesn't count? They're all Turing complete and all of them can do everything. All we need to do is learn the exact magic words.

I never said otherwise. My point is that Go is far harder to learn than they're implying. It certainly can't be learned over the weekend — well, maybe it can be, but the code you end up writing will Inevitably be full of resources leaks, panics, nil pointer issues, improperly handled errors, etc. You may be able to put together some basic logic, but you are far from understanding the language.

I don't think it's honest to parade Go as a language that's the paragon of simplicity that's easy to learn when that's simply not true. I also don't think it's honest for people to argue that addressing any of Go's countless warts would somehow make the language more complex or harder to learn.

I agree that it's very unlikely for someone to learn Go in a week and start writing flawless code.

But Go's real strength is in its readability, not writability. I think it's very much possible to learn Go in a week, then read clean Go code like the standard library and understand exactly what's going on. At least that's my interpretation of what it means for a new grad to be productive in Go in less than a week. Nobody is expecting someone new to write production-grade libraries with intricate concurrency bits in their first week, but they're already productive if they can read and understand it.

As a rule of thumb we spend 10x more time reading code than we do writing it (code reviews, debugging, refactors). So why not optimise for it?

As a fairly experienced engineer, I have to say that reading go code is what gives me the most pause. I find the amount of visual noise and lack of useful abstractions makes it so that to be efficient at reading code, I have to trust that the loop or the error handling code is doing what I expect. The issue with go is that the primitive operations are written `for i := 0; i < 10; i++` instead of `map` and `x, err := foo(); if err != nil {...}; bar(x)` instead of `y := bar(foo()?)`, which requires either presuming, or spending the mental energy ensuring the primitive was written correctly every time it is used.

I generally do the second, because doing the first is extremely tiring when reviewing code, but I dislike it immensely.

> This is a false dichotomy. One does not imply the other.

No it isn't, and yes it does. By definition, the more features I add to something, the more complex it becomes. So yes, Go achieves it's simplicity precisely by leaving out features.

> this great list of issues

I just picked three examples at random:

"Sending to an Unbuffered Channel Returns As Soon As the Target Receiver Is Ready"

"Send and receive operations on a nil channel block forver."

"Many languages have increment and decrement operators. Unlike other languages, Go doesn't support the prefix version of the operations."

All of these are behavior and operators that are documented in the language spec. So how is any of these a "footgun"?

> No it isn't, and yes it does. By definition, the more features I add to something, the more complex it becomes. So yes, Go achieves it's simplicity precisely by leaving out features.

More complex for whom? Not having generics made the compiler simple, but having to copy and paste and maintain identical implementations of a function (or use interface) adds more complexity for users.

Similarly, adding a better default HTTP client arguably makes Go more complex, but the "simple" approach results in lots of complexity and frustration for users.

> All of these are behavior and operators that are documented in the language spec. So how is any of these a "footgun"?

Perhaps I could have been clearer. I didn't mean that the entire list was of footguns, just that there are lots of confusing and unintuitive things beginners need to learn.

Some actual footguns off the top of my head:

- using Defer in a loop

- having to redeclare variables in a loop

- having to manually close the body of a http response even if you don't need it

Not only that but those behaviors are patently not footguns or unreasonable in any way
> "Send and receive operations on a nil channel block forver."

I literally can not imagine a worse behavior than my program blocking forever. Of all of the things my program can do, short of giving remote code execution, blocking is literally the worst one I can think of.

Goroutines blocking is normal procedure in a a Go program. It also isn't a problem, unless my code is broken and allows all Goroutines to block simultaneously...in which case the runtime automatically terminates the program with a Deadlock-Panic.

The behavior of nil-channels always blocking is on purpose, and tremendously useful in functions where we receive from multiple channels via `select`. It allows the function to easily manipulate it's own receive behavior simply by setting the local reference to the channel to `nil`.

Since `selects` can also have `default`, the resulting functions don't have to block either.

> No it isn't, and yes it does. By definition, the more features I add to something, the more complex it becomes.

Yes, and go opts to include features that unnecessarily increase complexity in this manner, such as nil values.

> All of these are behavior and operators that are documented in the language spec. So how is any of these a "footgun"?

By this logic, no language with a spec can have footguns. C and C++, notorious for their footguns, both specify their behavior in the spec, so do they not have any footguns?