-
Notifications
You must be signed in to change notification settings - Fork 17.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
iter: document general guidance for writing iterator APIs #71901
Comments
FWIW, that was a conscious decision. See for example the commit message here: (There was a separate comment on the rationale that I couldn’t dig up immediately, but I think in short it was something like it wasn’t 100% obvious if it was the right idiom, and I think also an element of “let’s first see how people use it for real”). |
Related Discussions (Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.) |
I understand the sentiment to deliberately not document until we first get experience, but I also agree with @mvdan that we should eventually (hopefully sooner rather than later) guidance on what to do. Doing something like |
That error result can communicate that iterator instantiation failed, but it cannot communicate that iteration itself fails. You'd need something like |
Another point of clarification that would be welcome: categorisation of iterators. I feel that differentiating single-use iterators from all other iterators was a poor choice. "Stateless" iterators (i.e. An analogy that comes to mind is linear systems vs nonlinear systems in control theory:
|
iter, errf := Foo()
for x := range iter {
...
}
if err := errf(); err != nil {
return err
} |
@gazerro Yes, that's the issue I was thinking of. Thanks. I'm not sure I'd be in favour of promoting this approach, though. |
Oops, of course, I meant to write something like that - so that an error (or a wrapped list of errors) can be returned once the iterator is done. |
This discussion is why we don't have general guidance about how to return errors. People don't yet agree. I think a commonly known method, such as |
While https://pkg.go.dev/iter does a good job at explaining the basics of iterators, it leaves out a few important bits of information which may be really useful when writing APIs with iterators. The two most important of them being:
The consensus seems to be to export funcs which return iterators, e.g.
func (*Foo) Bars() iter.Seq[Bar]
used likefor bar := range foo.Bars()
, rather thanfunc (*Foo) Bars(yield func(Bar) bool)
used likefor bar := range foo.Bars
. This is a bit more consistent with cases where one needs to supply parameters to obtain an iterator, as then the iterator must be a return parameter.See #66626 (comment), for example, where @adonovan originally proposed adding methods to
go/types
which were directly iterators.If an iteration can fail with an error, it's not obvious whether to return one top-level error, like
func Foo() (iter.Seq[Bar], error)
, or to provide an error at each iteration step, likefunc Foo() iter.Seq2[Bar, error]
. Arguments can be made either way, but I think fundamentally one can implement any reasonable semantics with either signature.The original proposal at #61897 seemed to clearly favor
iter.Seq2[Bar, error]
via itsfunc Lines(file string) iter.Seq2[string, error]
example, yet none of the value-error examples or text have survived into the final godoc we have today.As of today I think there is no clear consensus for errors; as recently as last October it was still being discussed as part of a new API proposal.
There may be other API conventions that the
iter
godoc should mention as well, but these two seem like the most important to me. I would suggest that we document these guidelines sooner than later, so that iterator APIs across the Go ecosystem can be reasonably consistent and predictable.The text was updated successfully, but these errors were encountered: