-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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
proposal: Go 2: add a new iterator syntax, package, interfaces #54047
Comments
Templates have the syntaxes
If the name err is already in scope, err is assigned iter.Close(), otherwise it brings a new err variable into scope after the loop. |
Adapting io/fs.WalkDir is a little tricky because you need to be able to skip directories, but you could do it by adding an fs.WalkIterator struct with a SkipDir method and Path, DirEntry, Error fields. It shouldn't be a Result iterator because the error is not necessarily final, for example, permission errors diving into a subdirectory.
In general, the wrappers to adapt existing standard library iterators to the new method are pretty straightforward to write. |
The suggested |
Also, FYI, there are a couple of iterator proposals kicking around inside the Go team. I hope that they will be published soon. |
It is my understanding that the for variable scope issue can't be solved in a backwards compatible way, so it needs some new syntax to indicate "this is the loop where that works as expected." It's also good to signal to readers when the native (fast!) looping will happen versus the method based looping (hopefully not slow, but probably slower since it needs a method call). I'd be happy if there were a |
I am not sure this syntactic sugar like this is needed. As an example, the bbolt library already has iterators, named cursors. With them you can iterate like this: cursor := bucket.Cursor() That seems easy enough without any extra syntax. |
@beoran I'd say I use iterator pattern a lot in my code, and it seems
|
@oakad , yes there are several styles of iterators already possible in Go. So that's why I am doubtful that syntactic sugar is really needed, or, that we have to officially bless one style of iteration on the language. |
Built in support for |
You can always do without a blessed iterator syntax. Why do we have three values for statements and That said, I'm less committed to the syntax part of this proposal than the interface part of this proposal. Having a standard interface for iteration means we can start building libraries that consume the standard interfaces, batch elements in slices, deduplicate repeated elements, etc., etc. |
@carlmjohnson well, there is a precedent for standard interfaces with the error type. There could probably also be a built in iterator type tho achieve this standardization, without adding any new other language features. |
Closing in favor of continuing the discussion at #54245. |
Author background
Experience Go programmer.
JavaScript, Python.
Related proposals
#20733 and #24282 address improving for loops. #40605, #43557, and #50112 address iterators. #17747, #34544, and other have added vet methods to ensure erors are checked on close. This proposal differs by using the
range
keyword to make the change more clear than reusingfor
, differentiating values, key values, and results, and by having a mandatory close mechanism that forces error handling, making the vet check less necessary.No.
It uses the implemented design and makes various future patterns possible.
Proposal
The following types would be added to the standard library in an iterators package (🚲 iters?).
The language spec would be changed to allow for loop statements of the following type:
Because all four iterator types have Value and Close methods, they are mutually exclusive for a type. As per #20733, the range block reassigns Value() on each loop. The Result and KeyValueResult types take an extra argument separated by a colon which only comes into scope after the loop is exited. (Open question: does Close() run after a panic?)
It makes a wide variety of iterator patterns easier to use. It is compatible with existing designs in the standard library. It solves the problem of users accidentally closing over for loop variable or forgetting to check the final error in a result iterator type. It allows for the creation of iterator libraries that iterate over chunks, subsets, permutations, etc.
See above.
See above. Subject to further discussion.
Go has a way of writing your own types that can be iterated over. First add method Iter() iterators.Value[myStruct] to our struct that just returns itself. Now we can use myStruct like this:
I believe so. That's why it uses
range
instead offor
. I'm not committed to this color of the bikeshed if someone can make it work withfor
but still be clearly readable.N/A because this is a new feature. Open question: should existing iterable types be magically opted into working with range statements? I think probably not.
It adds a new way to iterate, which is unforunate. On the other hand, it fixes two long standing sources of bugs: not realizing a loop reuses variables and not calling .Err() after scanning a row from bufio or sql.
No.
Costs
Harder because there is another form of iteration. But it makes it easier to write bug free code that uses an iterator.
Largely the cost is the introduction of a new concept.
They would need to know the new loop syntax.
Low. There would need to be a type analysis to ensure that the right type of iterator is used, e.g. you can't use a Result as a Value, etc.
Low.
TBD.
No.
The text was updated successfully, but these errors were encountered: