Proposal Details
The blog post about range-over-func gives the following example of a recursive iter.Seq over the values of a binary tree:
func (t *Tree[E]) All() iter.Seq[E] {
return func(yield func(E) bool) {
t.push(yield)
}
}
func (t *Tree[E]) push(yield func(E) bool) bool {
if t == nil {
return true
}
return t.left.push(yield) &&
yield(t.val) &&
t.right.push(yield)
}
I have built recursive iterators of similar patterns on several occasions, including one recently. The secondary method is necessary because iter.Seq does not return a final boolean indicating if it exited early or not. I remember that the original prototype had an extra boolean, but it was completely ignored by the iterator mechanism. However, every time I write a recursive iterator, it requires a function of a similar design, and I've been starting to think that having something like that in the standard library would be nice. It's essentially the equivalent of yield* in Python and similar things in a lot of other languages with generator functions.
For example,
package iter
// Push iterates over seq, calling yield for each value. It returns
// false if yield ever does and returns true otherwise.
//
// Push is primarily useful for building iter.Seq implementations that
// at some point yield all of the values of a different iter.Seq
// instance such as iterators over recursive data structures.
func (seq Seq[T]) Push(yield func(T) bool) bool {
for v := range seq {
if !yield(v) {
return false
}
}
return true
}
and the equivalent for iter.Seq2.
This would change recursive binary tree iterator example to just
func (t *Tree[E]) All() iter.Seq[E] {
return func(yield func(E) bool) {
if t == nil {
return true
}
_ = t.left.All().Push(yield) &&
yield(t.val) &&
t.right.All().Push(yield)
}
}
The need for _ = is a bit weird, but overall I'll take that minor awkwardness over rewriting this function all over the place.
I also considered a top-level function, something like func YieldAll[T any](seq iter.Seq[T], yield func(T) bool), but the method feels a bit nicer to me.
Edit: Forgot to mention alternative method names. I also thought of Via(), YieldTo(), and a few others. I'm very much not too picky about the bikeshed's color, though.
Proposal Details
The blog post about range-over-func gives the following example of a recursive
iter.Seqover the values of a binary tree:I have built recursive iterators of similar patterns on several occasions, including one recently. The secondary method is necessary because
iter.Seqdoes not return a final boolean indicating if it exited early or not. I remember that the original prototype had an extra boolean, but it was completely ignored by the iterator mechanism. However, every time I write a recursive iterator, it requires a function of a similar design, and I've been starting to think that having something like that in the standard library would be nice. It's essentially the equivalent ofyield*in Python and similar things in a lot of other languages with generator functions.For example,
and the equivalent for
iter.Seq2.This would change recursive binary tree iterator example to just
The need for
_ =is a bit weird, but overall I'll take that minor awkwardness over rewriting this function all over the place.I also considered a top-level function, something like
func YieldAll[T any](seq iter.Seq[T], yield func(T) bool), but the method feels a bit nicer to me.Edit: Forgot to mention alternative method names. I also thought of
Via(),YieldTo(), and a few others. I'm very much not too picky about the bikeshed's color, though.