The biggest problem is any string you pass as an argument to the fmt functions is moved onto the heap because interface{} is always counted as escaped from the stack (https://github.com/golang/go/issues/8618).
FWIW, that's not quite correct. For example, a string literal passed as a fmt argument won't be moved to the heap.
The upcoming Go 1.25 release has some related improvements that help strings in more cases. See for example https://go.dev/cl/649079.
Not quite - if the function accepting interface{} can be inlined (and other heuristics are groovy), then it won't escape.
Trivial example but it applies to real-world programs:
> cat main.go
package main
import "github.com/google/uuid"
func main() {
_ = foo(uuid.NewString())
}
func foo(s any) string {
switch s := s.(type) {
case string:
_ = "foo:" + s
}
return ""
}
# Build with escape analysis
> go build -gcflags="-m=2" main.go
# command-line-arguments
./main.go:9:6: can inline foo with cost 13 as: func(any) string { switch statement; return "" }
./main.go:5:6: can inline main with cost 77 as: func() { _ = foo(uuid.NewString()) }
./main.go:6:9: inlining call to foo
./main.go:6:24: uuid.NewString() does not escape
./main.go:6:9: "foo:" + s does not escape
./main.go:9:10: s does not escape
./main.go:12:14: "foo:" + s does not escape
It seems like the "..." of str = ... is the interesting part.
But the &str at the end is an additional heap allocation and causes an additional pointer hop when using the string. The only reason the function returns a pointer to a string in the first place is so that the nil check at the beginning can return nil. The calling code always checks if the result is nil and then immediately dereferences the string pointer. A better interface would be to panic if the argument is nil, or if that's too scary then:
func (thing *Thing) String() (string, bool) {
if thing == nil {
return "", false
}
str := ...
return str, true
}
But for a more long term solution in terms of reliability and overhead, it might be worth raising this as a feature request for the Go runtime itself. Type information could be provided via pprof labels on the allocation profiles.
[^1]: As opposed to profile that collect data only when activated, like the CPU profile. The heap profile is active from the beginning if `MemProfileRate` is set.
jasonthorsness•6h ago
ajd555•4h ago
giancarlostoro•4h ago
https://github.com/jasonthorsness/unlurker
I had no idea what this was... Is this an ongoing problem on HN or something?
ajd555•4h ago
giancarlostoro•4h ago
ajd555•4h ago
altruios•3h ago
Still: Seems ripe for abuse.
Bad actors ruin nice toys for the rest of us.
jasonthorsness•3h ago
jasonthorsness•3h ago
Also I use do use unlurker probably mostly as a stubborn insistence on using something I spent a lot of time on and to try to be more active, but ironically I just saw this article on the front page of the real site not on unlurker. I mostly develop in golang so found it pretty interesting albeit a bit extreme.
giancarlostoro•2h ago
I think we're going to see more people being accused of using AI because of word choice. The way I read your message outside of the one word you chose to use, it read like a genuine opinion of yours.
jrockway•4h ago
jasonthorsness•3h ago
As I mentioned in another reply, the weirdest thing about this comment chain is I saw this article on the front page, not unlurker (there wasn't much conversation yet when I posted so it would not have shown on the unlurker view I use).
Is "the author" a phrase AI prefers? Maybe I'll need to retire that along with "delve" and the em-dash and "you're absolutely right".
ajd555•3h ago
No, honestly the comment was more than legitimate, I guess the author part made me think of LLMs summarizing research papers.
Well, at least I've discovered unlurker out of this :)