Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Its worth calling out that abstractions can kill you in unexpected ways with go.

Anytime you use an interface it forces a heap allocation, even if the object is only used read only and within the same scope. That includes calls to things like fmt.Printf() so doing a for loop that prints the value of i forces the integer backing i to be heap allocated, along with every other value that you printed. So if you helpfully make every api in your library use an interface you are forcing the callers to use heap allocations for every single operation.



I thought surely an integer could be inlined into the interface, I thought Go used to do that. But I tried it on the playground, and it heap allocates it:

https://go.dev/play/p/zHfnQfJ9OGc


Go did use to do that, it was removed years ago, in 1.4: https://go.dev/doc/go1.4#runtime


Basically, anything that isn't a thin pointer (*T, chan, map) gets boxed nowadays. The end result is that both words of an interface value are always pointers [1], which is very friendly to the garbage collector (setting aside the extra allocations when escape analysis fails). I've seen some tricks in the standard library to avoid boxing, e.g. how strings and times are handled by log/slog [2].

[1]: https://github.com/teh-cmc/go-internals/blob/master/chapter2...

[2]: https://cs.opensource.google/go/go/+/refs/tags/go1.24.1:src/...


slog.Value looks incredibly useful.

Just imagine a day where database/sql doesn't generate a tonne of garbage because it moves to use something like that?


go1.15 re-added small integer packing into interfaces: https://go.dev/doc/go1.15#runtime


It didn't, actually. Instead go 1.15 has a static array of the first 256 positive integers, and when it needs to box one for an interface it gets a pointer into that array instead: https://go-review.googlesource.com/c/go/+/216401/4/src/runti...

This array is also used for single-byte strings (which previously had its own array): https://go-review.googlesource.com/c/go/+/221979/3/src/runti...


It didn't, do what? I would consider the first 256 integers to be "small integers" ;)

> Converting a small integer value into an interface value no longer causes allocation

I forgot that it can also be used for single byte strings, That's not an optimization I ever encountered being useful, but it's there!


> It didn't, do what?

Reintroduce “packing into interfaces”.

It did a completely different thing. Small integers remain not inlined.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: