Readit News logoReadit News
acatton · 2 months ago
> The wg.Go Function

> Go 1.25 introduced a waitgroup.Go function that lets you add Go routines to a waitgroup more easily. It takes the place of using the go keyword, [...]

99% of the time, you don't want to use sync.WaitGroup, but rather errgroup.Group. This is basically sync.WaitGroup with error handling. It also has optional context/cancellation support. See https://pkg.go.dev/golang.org/x/sync/errgroup

I know it's not part of the standard library, but it's part of the http://golang.org/x/ packages. TBH, golang.org/x/ is stuff that should be in the standard library but isn't, for some reason.

blixt · 2 months ago
I thought exactly the same thing. I use errgroup in practically every Go project because it does something you'd most likely do by hand otherwise, and it does it cleaner.

I discovered it after I had already written my own utility to do exactly the same thing, and the code was almost line for line the same, which was pretty funny. But it was a great opportunity to delete some code from the repo without having to refactor anything!

giancarlostoro · 2 months ago
> and the code was almost line for line the same, which was pretty funny.

One of the core strengths of Go is that it fits the zen of Python's " There should be one-- and preferably only one --obvious way to do it" and it does this very nicely.

mholt · 2 months ago
The extended standard lib is pretty great, but definitely can't keep the Go compatibility promise, so it's good that it's separate.
lagniappe · 2 months ago
>golang.org/x/ is stuff that should be in the standard library but isn't, for some reason

think of it as testing/staging before being merged into stable stdlib

linhns · 2 months ago
I do believe it’s backwards compatibility and evolving APIs
CamouflagedKiwi · 2 months ago
Except that it's a little bit too convenient, and highly useful things like errgroup stay there instead of having been adopted into the stdlib.
infogulch · 2 months ago
Wow how did I not know of this?!

How does it cancel in-progress goroutines when the provided context is cancelled?

wesleyd · 2 months ago
They have to all use the special context.
h4ck_th3_pl4n3t · 2 months ago
I never used errgroup but I realize that it's essentially the same what I end up implementing anyways.

With standard waitgroups I always move my states as a struct with something like a nested *data struct and an err property which is then pushed through the channel. But this way, my error handling is after the read instead of right at the Wait() call.

WhyNotHugo · 2 months ago
Looks like this isn’t usable with functions that take parameters. For that, you need wg.Add.
mwsherman · 2 months ago
There is mention of how len() is bytes, not “characters”. A further subtlety: a rune (codepoint) is still not necessarily a “character” in terms of what is displayed for users — that would be a “grapheme”.

A grapheme can be multiple codepoints, with modifiers, joiners, etc.

This is true in all languages, it’s a Unicode thing, not a Go thing. Shameless plug, here is a grapheme tokenizer for Go: https://github.com/clipperhouse/uax29/tree/master/graphemes

HeyImAlex · 2 months ago
Here’s my favorite post on the subject https://adam-p.ca/blog/2025/04/string-length/
debugnik · 2 months ago
Finally an article that doesn't pretend grapheme clusters are the be-all end-all of Unicode handling.

I'm saving this one. Not exactly how I'd explain it, but it's simplified enough to share with my current co-workers without being misleading.

virtualritz · 2 months ago
len() is also returning int instead of uint/uint64 in Go.

I do not use Go but ran into this when I had to write a Go wrapper for some Rust stuff the other day. I was baffled.

porridgeraisin · 2 months ago
Did not know about index-based string interpolation. Useful!

The part about changing a map while iterating is wrong though. The reason you may or may not get it is because go iterates in intentionally random order. It's nothing to do with speed. It's to prevent users from depending on the iteration order. It randomly chooses starting bucket and then goes in circular order, as well as randomly generates a perm of 0..7 inside each bucket. So if your edit goes into a bucket or a slot already visited then it won't be there.

Also, python is not an example to the contrary. Modifying python dicts while iterating is a `RuntimeError: dictionary changed size during iteration`

valzam · 2 months ago
Great list of why one can love and hate Go. I really did enjoy writing it but you never get the sense that you can be truly certain your code is robust because of subtle behaviour around nil.
jbreckmckye · 2 months ago
As a Go learner, the best explanation that has made sense to me is that interface types essentially just compose two pointers:

P1: The type and its method vtable

P2: The value

Once I understood that I could intuit how a nil Foo was not a nil Bar and not an untyped nil either

whateveracct · 2 months ago
ah yes of course - key semantics of `nil` should totally depend on deep implementation details in my language's runtime.

willem-dafoe-head-tap.gif

valzam · 2 months ago
I guess as a corollary, Go really rewards writing the dumbest code possible. No advanced type shenanigans, no overuse of interfaces, no complex composition of types. Then you will end up with a very fast, resource light system that just runs forever.
theshrike79 · 2 months ago
And code with zero ability to do fancy trickery ("expressive" as some people like to say) is easy to read even if the codebase - or even the language - is unfamiliar.

Which is really handy when shit's on fire and you need to find the error yesterday. You can just follow what happens instead of trying to figure out the cool tricks the original programmer put in with their super-expressive language.

Yes, the bug is on line 42, but it does two dozen things on the single line...

eweise · 2 months ago
You could say the same thing about any language. Writing "dumb" code is easier to understand especially in the small. But Go with function that take functions and return functions, channels and generics, can quickly look as complex as other languages.
h4ck_th3_pl4n3t · 2 months ago
Oh boi, all my RW mutexes for maps across goroutines would disagree.
usrnm · 2 months ago
To be fair, checking if an interface is nil is very dumb code, and the fact that it doesn't work is one of my biggest gripes with the language. In this case it's clearly the language (creators) who's dumb
gethly · 2 months ago
> Go really rewards writing the dumbest code possible

Simplicity is hard. You may see it as dumb, other see it as priceless attribute of the language.

Deleted Comment

Groxx · 2 months ago
>As an additional complexity, although string literals are UTF-8 encoded, they are just aribtrary collections of bytes, which means you can technically have strings that have invalid data in them. In this case, Go replaces invalid UTF-8 data with replacement characters.

No, it's just doing the usual "replace unprintable characters when printing" behavior. The data is unchanged, you have no guarantees of UTF-8 validity at all: https://go.dev/play/p/IpYjcMqtmP0

formerly_proven · 2 months ago
> This is different than, for instance, python, which has a “stable insertion order” that guarantees that this won’t happen. The reason Go does this: speed!

In Python you'll actually get a RuntimeError here, because Python detects that you're modifying the dictionary while iterating over it.

DarkNova6 · 2 months ago
As somebody who only views Go from a distance, I see this list as a combination of „what‘s the big deal?“ and „please don‘t“.
OvervCW · 2 months ago
I'm amused by posts like this because it shows that Go is finally slowly moving away from being an unergonomically simplistic language (its original USP?) to adopt features a modern language should have had all along.

My experience developing in it always gave me the impression that the designers of the language looked at C and thought "all this is missing is garbage collection and then we'll have the perfect language".

I feel like a large amount of the feeling of productivity developers get from writing Go code originates from their sheer LOC output due to having to reproduce what other languages can do in just a few lines thanks to proper language & standard library features.

pjmlp · 2 months ago
Unfortunely given that the authors are also related to C's creation, it shows a common pattern, including why C is an insecure language.

> Although we entertained occasional thoughts about implementing one of the major languages of the time like Fortran, PL/I, or Algol 68, such a project seemed hopelessly large for our resources: much simpler and smaller tools were called for. All these languages influenced our work, but it was more fun to do things on our own.

From https://www.nokia.com/bell-labs/about/dennis-m-ritchie/chist...

Go grew up from the failed design with Alef in Plan 9, which got a second chance with Limbo on Inferno.

https://en.wikipedia.org/wiki/Alef_(programming_language)

> Rob Pike later explained Alef's demise by pointing to its lack of automatic memory management, despite Pike's and other people's urging Winterbottom to add garbage collection to the language;

https://doc.cat-v.org/inferno/4th_edition/limbo_language/lim...

You will notice some of the similarities between Limbo and Go, with a little sprikle of Oberon-2 method syntax, and SYSTEM replaced by unsafe.

https://ssw.jku.at/Research/Papers/Oberon2.pdf

DanielHB · 2 months ago
I remember when I first got out of uni and did backend Java development, I thought I was incredibly productive because of the sheer amount of typing and code I had to pump out.

After doing a bit of frontend JS I was quickly dissuaded of that notion, all I was doing was writing really long boilerplate.

This was in the Java 6 days, so before a lot of nice features were added, for example a simple callback required the creation of a class that implements an interface with the method (so 3 unique names and a bunch of boilerplate to type out, you could get away with 2 names if you used an anonymous class).

liampulles · 2 months ago
As a Go developer, I do think that I end up writing more code initially, not just because of the lack of syntactic sugar and "language magic", but because the community philosophy is to prefer a little bit of copying over premature abstraction.

I think the end result is code which is quite easy to understand and maintain, because it is quite plain stuff with a clear control flow at the end of the day. Go code is the most pleasant code to debug of all the languages I've worked with, and there is not a close second.

Given that I spend much more time in the maintenance phase, it's a trade-off I'm quite happy to make.

(This is of course all my experience; very IMO)

petralithic · 2 months ago
More like, let's throw away the last 75 years of programming language theory advances, only to rediscover them again ourselves, with much hardship.
eptcyka · 2 months ago
How is the boxed interface problem enabling better ergonomics for Go? I find that most quirks listed here are not making the language any better.

Deleted Comment

deivid · 2 months ago
C at least has const ptr. In go I've seen pointers mutated 7 levels down the callstack. And of course, the rest of the sphagetti depended on those side effects.

C is so limited that you would try to avoid mutation and even complex datastructures.

Go is "powerful" enough to let you shoot yourself much harder.

Go with `const` and NonNull<ptr> (call it a reference if you need) would be a much nicer language

0x696C6961 · 2 months ago
If you think Go and C are that similar then you don't know either.
tptacek · 2 months ago
If you don't write Go at all, this blog post isn't going to be useful to you, and you aren't its audience. It's fine not to have an apt take for a programming-language-specific article!
tapirl · 2 months ago
The wording "Subtleties" used here is some weird/improper. I see nothing subtle here. They are all basic knowledge a qualified Go programmer should know about.

They are many real subtleties in Go, which even many professional Go programmers are not aware of. Here are some of them: https://go101.org/blog/2025-10-22-some-real-go-subtleties.ht...

NuclearPM · 2 months ago
The examples in your link don’t seem to be very useful compared to the subject of this post.

“for true {...} and for {...} are not eqivalent”

So what? The compiler will tell you the first time you try to run that “for true” abomination that it is invalid code.

tapirl · 2 months ago
Subtleties are not necessary to be very useful. They, are just real subtleties. :)

> > “for true {...} and for {...} are not eqivalent”

> So what? The compiler will tell you the first time you try to run that “for true” abomination that it is invalid code.

It teaches you know that, when you write

    func bar() int {
         for true {
              ...
         }
         return 0 // whatever
    }
You can write it as

    func bar() int {
         for {
              ...
         }
    }
The compiler will not teach you this. ;D

Usefulness might be subjective. Personally, the last two subtleties mentioned in the article are useful for me too.

You may find some useful (in your opinion) subtleties in the Go Details and Tips 101 book: https://go101.org/details-and-tips/101.html, and some since-Go-1.22/3 ones here: https://go101.org/blog/2024-03-01-for-loop-semantic-changes-... and https://go101.org/blog/2025-03-15-some-facts-about-iterators...