Skip to content

proposal: strings: add a Join method to Builder #49546

Closed
@muhlemmer

Description

@muhlemmer

Sometimes, I find myself wanting to join a slice of strings and append the result to a strings.Builder. This can be done by:

  1. Use something like Builder.WriteString(strings.Join([]string{"foo", "bar"}, ", ")), less coding, but results in 1 extra allocation.
  2. Write my own joining loop against the builder, basically duplication of code of the current strings.Join function.

Currently, strings.Join() already uses a strings.Builder. This issue proposes to move the code from this function into a method of strings.Builder. The current strings.Join() function will become a wrapper which allocates a new builder and calls this new method for further processing.

Example (adjusted copy of strings.Join()):

type Builder struct {
	strings.Builder
}

func (b *Builder) Join(elems []string, sep string) {
	switch len(elems) {
	case 0:
		return
	case 1:
		b.Grow(len(elems[0]))
		b.WriteString(elems[0])
	}

	n := len(sep) * (len(elems) - 1)
	for i := 0; i < len(elems); i++ {
		n += len(elems[i])
	}

	b.Grow(n)
	b.WriteString(elems[0])
	for _, s := range elems[1:] {
		b.WriteString(sep)
		b.WriteString(s)
	}
}

Benchmarks code:

func Benchmark_Builder_Join(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var b Builder
		b.Join([]string{"Hello", "World!"}, ", ")
	}
}

func Benchmark_Join_and_WriteString(b *testing.B) {
	for i := 0; i < b.N; i++ {
		var b Builder
		b.WriteString(
			strings.Join([]string{"Hello", "World!"}, ", "),
		)
	}
}

Benchmark run:

go test -benchmem -bench . 
goos: linux
goarch: amd64
pkg: github.com/muhlemmer/pbpgx
cpu: AMD Ryzen 9 5900HX with Radeon Graphics        
Benchmark_Builder_Join-16               30865467                72.17 ns/op           16 B/op          1 allocs/op
Benchmark_Join_and_WriteString-16       19650562               138.8 ns/op            32 B/op          2 allocs/op
PASS
ok      github.com/muhlemmer/pbpgx      5.132s

Items open for discussion:

  1. Name of the method (Join, AppendJoin or WriteJoin?).
  2. Should the method return total bytes written, as returned by WriteString()?
  3. Should the method return error, as returned by WriteString()? (Is always nil)

Related: PR #42850, which got put on hold for not going trough the proposal process (and duplicates code)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions