How does bytealg.MakeNoZero() work?

64 views
Skip to first unread message

Mike Schinkel

unread,
Jun 26, 2024, 2:38:42 AM (4 days ago) Jun 26
to GoLang Nuts Mailing List
Can someone help me understand how `bytealg.MakeNoZero()` in the Go standard library works, please?


In the source it is a `func` without a body, and in my own code that won't compile in Go; I get "missing function body."  Where is its implementation and how does the Go compiler handle it?

I discovered `bytealg.MakeNoZero()` looking into the source for `strings.Builder`:


I was considering following the advice in Go Proverbs that "A little copying is better than a little dependency" but I obviously found that I cannot copy it to my own package and compile it, at least not as-is.

I wanted to create my own version of `strings.Builder` that has a `Rewind()` method to allow slicing one or more characters from the internal `buf` buffer, e.g.:


func (b *StringBuilder) Rewind(n int) {
   if n > len(b.buf) {
     n = len(b.buf)
   } 
   b.buf = b.buf[:len(b.buf)-n]
}

I could of course modify the code of `strings.Builder` to replace `bytealg.MakeNoZero()` but then I would have a less performant string builder, especially for larger strings:


Any insight into `bytealg.MakeNoZero()` would be appreciated.

-Mike 

Axel Wagner

unread,
Jun 26, 2024, 2:47:38 AM (4 days ago) Jun 26
to Mike Schinkel, GoLang Nuts Mailing List
It is defined in the runtime and go:linkname'd into the bytealg package:

A function declaration without type parameters may omit the body. Such a declaration provides the signature for a function implemented outside Go, such as an assembly routine

How that works is, of course, implementation defined. It may be using assembly or, as in this case, with the body being provided by the linker later.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/FEC2DD8C-7664-425E-8905-A21D49257975%40newclarity.net.

Axel Wagner

unread,
Jun 26, 2024, 2:54:48 AM (4 days ago) Jun 26
to Mike Schinkel, GoLang Nuts Mailing List
And in terms of practical advice:

You might be able to use go:linkname yourself to get access to that functionality from the runtime. But note that go:linkname is being locked down in Go 1.23, so that is not a future-proof plan.

Your best bet is probably to file a proposal to get the functionality you want for strings.Builder. Or to get an exported API (say in the runtime package) to allocate non-zeroed memory.

Otherwise, you might be able to use `unsafe` to access the unexported fields of `strings.Builder`. That is, you can define your type as
type MyBuilder struct {
    strings.Builder
}
and then add methods to that which use `unsafe` to do what you want. Though that will, of course, also be dangerous and should be guarded with build tags for the used Go version, at the least.

Mike Schinkel

unread,
Jun 26, 2024, 3:07:50 AM (4 days ago) Jun 26
to Axel Wagner, GoLang Nuts Mailing List

On Jun 26, 2024, at 2:46 AM, Axel Wagner <axel.wa...@googlemail.com> wrote:

It is defined in the runtime and go:linkname'd into the bytealg package:

Thank you for that link.

On Jun 26, 2024, at 2:54 AM, Axel Wagner <axel.wa...@googlemail.com> wrote:

And in terms of practical advice:

You might be able to use go:linkname yourself to get access to that functionality from the runtime. But note that go:linkname is being locked down in Go 1.23, so that is not a future-proof plan.

Your best bet is probably to file a proposal to get the functionality you want for strings.Builder. Or to get an exported API (say in the runtime package) to allocate non-zeroed memory.

My email to the list was actually my precursor research for exactly that; to submit a proposal to add Rewind() to strings.Builder{}.  My proposal will elaborate on a common use-case where I would see the need for that functionality along with a mention about the alternate being to use go:linkname.

Then I might mention the proposal on that thread about locking down go:linkname.  :-)

Otherwise, you might be able to use `unsafe` to access the unexported fields of `strings.Builder`. That is, you can define your type as
type MyBuilder struct {
    strings.Builder
}
and then add methods to that which use `unsafe` to do what you want. Though that will, of course, also be dangerous and should be guarded with build tags for the used Go version, at the least.

Nah, do not want to do that.  

But thank you for elaborating in case I did.

-Mike

Reply all
Reply to author
Forward
0 new messages