In part of the comment yes, kind of, but the comment begins by saying "Iterators definitely have one of the strangest syntaxes I've seen". As there is no syntax specific to iterators in Go, I find this a bit hard to understand.
Well, yes, that's the thing: you don't get any special syntax for generators (like "yield" keyword), which makes them look quite weird compared to other languages that have native support for them. You need to have very clunky and verbose syntax (at least I view it as such) which consists of having to define an extra nested closure and use a function pointer that was passed to you. Having a new keyword would allow for a much nicer looking generator functions, but that would break all existing tooling that doesn't yet support that keyword (and potentially break existing programs that use yield as a variable name or something like that).
Seems like a total non-issue to me. It’s conceptually very easy to grasp and follows the normal Go syntax for defining functions. And what percentage of your code base is really going to consist of custom iterators? A syntactic shortcut might save you two lines of code for every 5000 you write. A lot of Go programmers will probably never write a custom iterator from scratch. The important thing is to make the custom iterators easy to use, which I think has been achieved. I’m sure they’ll consider adding some syntax sugar in time, but it would be a trivial convenience.
The benefit of Go’s generator implementation is a huge simplificación of the language semantics compared to other approaches. The generator function has no special semantics at all, and when used with ‘range’, all that occurs is a very simple conversion to an explicit loop repeatedly calling the function. Other popular approaches require either special runtime support for coroutines of some form, or a much more elaborate translation step within the compiler.
It's just the visitor pattern, taught in software engineering 101. A function that takes a callback function that gets called for each visited value. Nothing strange about it. Many standard library functions such as sync.Map.Range or filepath.Walk have always used it. The new thing is that it now gets easier to use on the caller side.
The sync.Map.Range, filepath.Walk and other similar functions with visitor pattern in standard Go packages will remain there forever because of backwards compatibility. This means that new functions must be added to standard Go packages in order to be able to use them with iterators starting from Go 1.23. This complicates Go without reasonable benefit:
- You need to be able maintaining code with multiple ways to iterate over various collections in standard Go packages.
- You need to spend time on deciding which approach for iteration to use when you write new code.