10 comments

[ 3.4 ms ] story [ 33.5 ms ] thread
> Another takeaway here, as always, is not to trust everything LLMs say.

I would go even farther and say to not trust anything they say. Always be skeptical, always verify.

> Using empty structs also hurts readability

An empty struct is idiomatic and expected to be used in a Set type. When/if the memory optimization is reintroduced, no code change will be needed to take advantage of it.

So what is this article about?

1. How to do sets in Go?

2. What changed between Go 1.24 and 1.25?

3. Trusting an LLM?

4. Self-hosted compilers?

It is not clear at all. Also there are no conclusions, it's purely a waste of time, basically the story of a guy figuring out for no reason that the way maps are implemented has changed in Go.

And the title is about self-hosted compilers, whose "advantage" turned out to be just that the guy was able to read the code? How is that an advantage? I guess it is an advantage for him.

The TypeScript compiler is also written in Go instead of in TypeScript. So this shouldn't be an advantage? But this guy likes to read Go, so it would also be an advantage to him.

I wonder if the compiler really needs to allocate 1 byte so you can get the address of the struct {}

In the general case then yes, but here you can't take addresses of dictionary values (the compiler won't let you) so adding 1 byte to make a unique pointer for the struct {} shouldn't be necessary.

Unless it is used in the implementation of the map I suppose.

So I conjecture a bit of internal magic could fix this.

It's worth noting that the "self-hosted compiler" thing here is a red herring.

E.g. the JVM is a C++ project, but you can easily read the HashMap implementation, because it's part of the standard library, not part of the runtime.

In Go, hashmap implementation is pretty low level. Even linker carries some parts of its implementation details.
Empty struct is good for representing non-nil zero-length information, for example this is ideal for many use cases where channels are involved. Or of you have a http route and you want to return empty response(200 OK or 204 No Content, instead of error).

Boolean on the other hand inherently contains two information: either true or false. ie. there will always be information and it will always be one of two values.

This is similar to *struct{} where we can signal no information, or false, by returning/passing nil or initiated pointer to empty struct as true/value present.

For maps, bool makes more sense as otherwise we just want a list with fast access to determine whether value in the list exists or not. Which is often something we might want. But it should not detract form the fact that each type has its own place and just because new implementation for maps ignores this, in this particular use, case does not make them worse than previous version.

tl;dr it is good to know this fact about the new swiss maps, but it should not have any impact on programming an design decisions whatsoever.

Interesting how the Go team is the utmost example of thinking through and bikeshedding ad infinitum even the tiniest angles of each proposal (something that I like a lot by the way), which is part of the reason that popular feature requests take years to come, and others such as the `Set` type are binned because of not providing enough added value.

But an implementation change that will for sure baloon the memory usage of everybody's code making heavy use of Hashmap-as-set (a popular idiom)? Yeah no problem, change shipped.

Rust HashSets are HashMaps with an empty type as the value type, but the compiler actually optimizes away the storage for the keys based on the type being empty. Go doesn't bother to either define a set type like most languages do, or to optimize the map implementation with an empty type as the value type