r/golang
Show and TellPackageFeedback
I built ko, a small iter.Seq collection helper package for Go
- Looking for API feedback on a small
iter.Seqhelper package ko: typedSeqandSeq2chains backed by Go iterators- Is this
Seq/Seq2API idiomatic, or too much abstraction for Go? - A tiny lodash-style helper package for Go collections, built on
iter.Seq
Hi r/golang,
I have been working on a small Go package called ko:
https://github.com/go-kod/ko
It is a typed collection helper package for common slice and map pipelines. The current design is built around Go iterators:
Seq[T]is based oniter.Seq[T]Seq2[K, V]is based oniter.Seq2[K, V]- intermediate operations stay sequence-based where possible
Collect()is the explicit materialization boundary- there are no runtime dependencies outside the standard library
The package is not meant to replace normal loops. I still reach for loops when they are clearer. The goal is to make common transformation pipelines compact without repeatedly converting between slices and maps in the middle of the chain.
Example:
got := ko.Of(1, 2, 3, 4).
Filter(func(item int, _ int) bool {
return item%2 == 0
}).
Map(func(item int, _ int) string {
return strconv.Itoa(item * 10)
}).
Collect()
// []string{"20", "40"}Map-style pipelines use Seq2:
got := ko.Map(map[string]int{"a": 1, "bb": 2}).
Filter(func(_ string, value int) bool {
return value > 1
}).
Map(func(key string, value int) (int, string) {
return len(key), strconv.Itoa(value)
}).
Collect()
// map[int]string{2: "2"}Seq-to-Seq2 operations also stay lazy until Collect():
byLength := ko.Slice([]string{"go", "ko", "kod"}).
ToMap(func(item string, _ int) (int, string) {
return len(item), item
}).
Collect()
// map[int]string{2: "ko", 3: "kod"}In that example, duplicate keys are resolved only when the Seq2 is collected into a Go map, so the last value for key 2 wins.
There are also small sequence constructors:
got := ko.Range(1, 6).
Filter(func(item int, _ int) bool {
return item%2 == 1
}).
Collect()
// []int{1, 3, 5}Some of the API surface includes Filter, Reject, Map, FilterMap, FlatMap, DistinctBy, Chunk, Window, GroupBy, Keys, Values, and ToSlice.
I would appreciate critical feedback on the API shape:
- Does
Seq[T]/Seq2[K, V]feel natural for iterator-backed Go code? - Is
Collect()the right name for the materialization boundary? - Are methods like
ToMap,GroupBy,Chunk, andWindowworth having in a small package? - Are any return types surprising?
- Does this feel useful, or would you keep helpers like this local to each project?
- Are there methods that should be removed to keep the package more idiomatic?
I am especially interested in feedback from people already using Go iterators in real code.
I built ko, a small typed collection helper package for Go:
https://github.com/go-kod/ko
It provides Seq[T] and Seq2[K, V] chains backed by iter.Seq / iter.Seq2, keeps intermediate operations sequence-based where possible, and uses Collect() as the explicit materialization point.
I am looking for API feedback from Go developers, especially around whether this style feels idiomatic or like unnecessary abstraction.
A bit more context: this started as a small lodash-style helper package, but I refactored it to use iter.Seq more thoroughly. The main design constraint is that intermediate operations should remain sequence-based instead of collecting into slices or maps between steps.
The implementation is intentionally small and dependency-free. I am trying to find the line between useful collection helpers and an API that feels too clever for Go.