Posted by mpweiher 6 days ago
Still, this example has other issues (naked range over a channel?!) potentially contributing to the author’s confusion.
However, this post was also written almost a decade ago, so perhaps it’s a result of being new to the language? If I cared to look, I’d probably be able to find the corresponding HN thread from that year full of arguments about this, hah.
This isn't your rule of thumb, it's the only practical way to do it. The problems arise when you have multiple goroutines writing to a channel, which is the case here.
> Still, this example has other issues (naked range over a channel?!) potentially contributing to the author’s confusion.
You sound way more confused than the author. I think you've misunderstood what the (admittedly very abstract) example is supposed to be doing.
It is not clear from the example, but I presume there would multiple players, i.e there will calls of the form:
g.HandlePlayer(p1)
g.HandlePlayer(p2)
..
in such a case one player closing the channel would affect rest of the producers too.If you don't understand how to use channels, you should learn first. I agree that you might have to learn by experimenting yourself, and that
a) there is a small design flaw in Go channels, but one that is easily fixed; and
b) the standard documentation does not teach good practices for using channels.
First, the design flaw: close(channel) should be idempotent. It is not. Is this a fatal flaw? Hardly. The work around is trivial. Create a wrapper struct with a mutex that allows you to call Close() on the struct, and that effects an idempotent close of the member channel. Yes this is a bit of work, but you do it once, put it in a re-usable library, and never bother to think much about it again.
b) poor recommended practices (range over channel). The original article makes this mistake, and it is what causes his problem: you can never use range over a channel in production code. You must always do any select on a channel alongside a shutdown (bailout) channel, so there will always be at least two channels being select-ed on.
So yes. The docs could be better. It was immediately obvious to me when I learned Go 12 years ago that nobody at Google ever shuts down their services deliberately. Fortunately I was learning Test Driven Development at the time. So I was forced to figure out the above two rules pretty quickly.
Once those two trivial fixes are in place, Go sails. There are Go libraries on github that do this for you. You don't even have to think. But you should.
Handling errors is only as verbose as you want it to be. You do realize you can call a function instead of writing if err != nil so much, right? Sheesh.
Go _is_ something of a sharp tool. Maybe we need to put a warning on it: for mature audiences only.
This has been said for other languages, and it turns out no one is mature enough to consistently make it work without issues. The world has moved on; we can have proper tools that won't shoot your leg off.
Why risk misusing the sharp tool when you can just use something safe to accomplish the same thing?
I quickly fell in love with Golang... and quickly fell out of love with it as well. It's a language that is super easy to love but it just does not seem to be suited for big codebases at all.
What if you spawned a new goroutine that waits for a waitgroup to complete and then closes the channel?
But in any case you will end up using a wrapper on either