5 ms·
That's just that they picked a worse case of zero value for slices and maps, presumably for performance gains.
by the_gipsy 2y ago
That's just that they picked a worse case of zero value for slices and maps, presumably for performance gains.
- tsimionescu 2y agoIt should be noted that slices and maps are completely opposite ends of how they behave in relation to nil in Go. A nil slice is just an empty slice, there is no operation you could do with one that will fail if done with the other. In contrast, a nil map doesn't support any operation whatsoever, it will panic on doing anything with it.
- the_gipsy 2y agoYou're quite mistaken. You can use len() on both nil maps and slices, and it will return zero (as with empty ones). Panic occurs on both nil assignments. But then, access only panics on nil slices - nil maps produce the zero value. It's horrible. https://go.dev/play/p/2KFOoJ0oyWB https://go.dev/play/p/2KFOoJ0oyWB
- mxey 2y agoAccess on an empty slice would also panic because of out of bounds. So there’s no useful distinction there. However, nil slices work just fine when calling append on them, while writing to a nil map in any way will panic.
- tsimionescu 2y agoRight, forgot that len() works on nil maps, and I was really not aware that reading from a nil map is not an error, that's crazy. For the nil slice though what I said remains true: a nil slice is the same thing as an empty slice. Of course reading from or writing to its first element panics, given that it doesn't have any elements. The same would have happened if you had initialized it as `var ns []int = make([]int, 0)` or `ns := []int{}`.
- the_gipsy 2y agoAh now I get it, yes you're right, they behave the same. Ironically, just today I read that in the next release they will add some JSON annotation to distinguish nil slices (omitzero): https://tip.golang.org/doc/go1.24 https://tip.golang.org/doc/go1.24
- 9rx 2y agoThe slice type is an implicit struct, in the shape: struct { data uintptr len int cap int } Which is usable when the underlying memory is set to zero. So its zero value is really an empty slice. Most languages seem to have settled on empty slice, array, etc. as the initialized state just the same. I find it interesting you consider that the worst case. Maps are similar, but have internal data structures that require initialization, thus cannot be reliably used when zeroed. This is probably not so much a performance optimization as convention. You see similar instances in the standard library. For example: var file os.File file.Read([]byte{}) // panics; file must be initialized first.
- bbatha 2y ago> Maps are similar, but have internal data structures that require initialization, thus cannot be reliably used when zeroed. Its a performance thing, the map structure requires a heap allocation even with zero elements. This is because the map structure is type generic without being fully monomorphized.
- 9rx 2y agoThe heap allocation could transparently happen at use. The only additional performance overhead that would bring is the conditional around if it has already been initialized or not, which is negligible for modern computers. Go is not obsessed with eking every last bit of performance anyway. But, that is not the convention. It is well understood that if a struct needs allocations that you must first call a constructor function (e.g. package.NewFoo). It is reasonable to expect that map would stick to the same convention.