I can't believe youtube still has this problem with porn bots spamming comments in the first few minutes of a video. Great video. Annoying that YT is still trash
i think iterators are a good addition, i've started preferring them a lot over regular loops since i started using rust a while back, nice to see them in go, too!
Great video. I still think the iterators look overly complex, but... you gave really good examples of valid use-cases and it didn't look "that bad". Also, it's not fair that you have such a pleasant voice to listen to haha.
Honestly, I don't understand why so many people were opposed to this feature. It's just a fairly regular implementation of internal iterators (the foreach method found in several languages is an example of an internal iterator). Despite the fact that I prefer external iterators, this is quite a nice addition to Go. External iterators are a bit easier to reason about, but are usually slower, since every single iteration is a function call like `iterator.next()` This is probably the reason why they went with internal iterators, it's a much thinner layer of abstraction on top of a single for loop.
The only real issue I had was that it could be used to obscure concurrency, which I think is something that should always be rather explicit, so I'm really glad it's fixed. I think for others: Alot of Go users are very protective about the language, mainly because it is incredibly simple, and there's a fear that adding too much might cause it to lose that simplicity.
Go iterators still require function calls (the yield function) to decide whether to continue the iteration or stop. The difference is that the function is implicitly provided by the language. The main problem most people saw with iterators in Go is that the syntax for defining them looks quite alien until you get used to it, and it introduced more "magic" to the language for the machinery that converts a high-order function (the iterator function, which returns a function that takes another function) to the range for loop. As a user, they're quite simple to use, but they're a little awkward to write.
@@maleldil1 Yeah, you're right. In an external iterator every iteration calls a method on the iterator struct, that contains the state of the iteration. In Go's internal iterators every iteration calls the anonymous function that contains the body of the loop. So the main difference is that you don't have to define a struct that conforms to some interface, instead you define a function that returns a function that serves the function of an iterator. That is probably the main source of confusion.
I believe that the prevention of simultaneous loop-body execution was likely because in the original proposal for range-func, the goal was to (eventualy) use coroutines to implement the back and forth between the ranged-over iterator and the range loop (similar to python generators) as an optimization instead of repeatedly calling the yield closure. Coroutines would be passing a single thread of control back and forth, which would completely break if the yield function / loop body could be started multiple times concurrently. Coroutines aren't the fastest way to implement most loops, as deep inlining would allow the body of the range loop to be inlined into the iterator's push-loop creating a single loop with no additional function calls. However this requires that the iterator and the loop body both be inlineable, and the resulting combination of the two itself be inlinable to have a chance at removing all the layers of abstraction. Instead with coroutines, both the loop body and iterator body can be completely independent with either an indirect (predictable) jump between them in the best case or a more involved but still fast coroutine switch instead of building a new stack frame every iteration. By putting in the error now, all valid use of range-for shouldn't break the coroutines if/when they are added to the process. They can always remove the restriction later if needed without breaking backwards compatibility. However, doing the reverse, allowing parallel iteration because the closures are safe to call in goroutines would require them to either break any code that relies on that behaviour to use coroutines, or detect when it's not safe and leave the current implementation in place, resulting in vestigial code path(s) to cover the compatibity cases, not to mention the complexity needed in the compiler to statically determine when it's safe to optimize using coroutines. Coroutines aren't being used for this yet, but the coroutine code does exist (internal to the stdlib/runtime) and is in use to implement iter.Pull/Pull2 to allow one or more pull iterators to be used at the same time without needing goroutines to track the state of each iterator.
As a swifty and crystalist, I don't understand when Go does a fairly minimal, QOL change and the community of developers just kind of lose it. I think Go programmers kind of drink too much in the 'the language should be simple!' kool-aid but ignore how much 'batteries included' the core library has. I would go as far and say that Go is not really as simple as people claim it is. So is Swift and Swift also has a huge 'batteries included' library. Plus, we all 'need' iterators. It is the most powerful data manipulation tool we have and Golangers were like "Nope. I will never USE this." Okay? No one should ask that. I dont use everything in the standard library. It is nothing to something to complain about.
From the pov of Swift and Crystal, then I definitely agree with your conclusion. However, a lot of Go developers come from the viewpoint of Java and C++, which are very complex languages comparatively. The stdlib of Go is inspired by GlibC and other languages, which is typically much simplier that the stdlib of C++ which can be abhorrent to look at. As for iterators, I agree, I think they are worthwhile. My only concern was that you could hide concurrency in them, which I'm really glad they've resolved.
I think Swift definitely implements this type of "concurrent custom iterator" more elegantly too. It's at least way easier to read and understand. Like, I can define a custom iterator, but then all of concurrency logic is a separate implementation. IteratorProtocol, Sendable, and AsyncIterator all different protocols to solve different problems.
Nice video, loved the quality for this last videos. What do you think about Golang development team only supporting the last 2 releases, maybe is already time to create an LTS version.
I think with the backwards compatibility support they've added since go 1.22, I'm happy with only supporting the last two releases. I tend to prefer moving fast rather than the alternative (python 2/3 debacle)
I like them, I think, but I'm worried about syntax in Go. It already looks overly verbose, clunky and sometimes unreadable and this piles on another thing on top. Imagine a semi-complex codebase that uses concurrency with channels, is generic and has a function iterator somewhere in the mix. I shudder thinking just how awful this would look.
Hi, first of all I loved this video. Could you perhaps make one explaining why this implementation is favored over other implementations? I’m seeing a lot of debate online but I’m interested in learning your take (or perhaps the go team’s take) on why this implementation is favored over others. Thanks :)
the fact that there needs to be seperately defined seq and seq2 func for a lot of things is my biggest issue with iterators. but that honestly falls back to a more fundamental lack in go typeing of type unions.
Hey! off topic, but I'm about to pull the trigger on the Keychron V10 Max you reviewed last video. But I had a couple questions - do you need a wristrest for comfortable use? and what was the KB you mentioned in the end of the video - is it substantially better than the keychron in your opinion?
I'm a fan of wrist wrests, mainly because I don't have as good form for typing, so if you're the same the V10 might not be perfect for you. The keyboard at the end was the ZSA Moonlander, that's currently my favorite keyboard and the one that I use the most at the moment. If you have the budget for it, then I highly recommend it! feel free to jump on my Discord and ping me if you want some more info.
I'm not keen on the new iterators. I'd have liked it if they did it more in the shape of an interface. PHPs Iterator Interface, for example. That is way easier to understand, than this mess. A mess of functions within functions and some Yields thrown in. It makes things confusing. All in all, I'm not going to write my own iterators in this way, but I appreciate the option. Back when Generics were introduced, I too though, that I'd never use them, but there were situations, where they came in handy.
I tried this but I didn't like it much. I wanted to yield a key & value ( Seq2 ) but also an error as the iterator was fallible. But, there's no way of doing that.
I wanna ask, I have seen your pass video about a password manager and I am really liking it, before I implement it, I wanna ask you if you are still using it, if so that confirms to me that it is reliable. Also any tips about it will be welcomed!
This looks like rust for me, with less features I don't say ot's bad or good, as all the languages can achieve a working app,, use thame language that you like or the one that,is used by your local businesses
The go language is medieval in comparison to others. It gives nothing of value to a modern system devs. Just a hype.The code looks wierd and difficult to suppport
@@dreamsofcode i can not state that a struct implements this and this interface. There's no garantee that nobody will change methods contracts. I can not create normal classes with normal methods. I can not override a method. I started to learn go and had found that c# is much better, more universal, and has the same performance. The code is much more clean and clear than the go code.
@@MaximT Implicit interfaces are actually a huge strength in my opinion. It allows you to perform amazing decoupling when used properly. I think I should do a video on it!
I can't believe youtube still has this problem with porn bots spamming comments in the first few minutes of a video. Great video. Annoying that YT is still trash
Its really bad ATM! No way to block based on keywords either as they just act innocuous
@@awesomedavid2012 Give them a break, I’m sure they are iterating
@@dreamsofcodeits cuz they are using function iterators
@@maximsbeyti1224 🤣🤣🤣
Rust mentioned in a positive light in a Go video? Let’s goooo! 🙌
I will be the peacemaker between the two communities!
@@dreamsofcode I genuinely believe that too- keeping slippin’ em in brother 🦀
Let's ruuust!
i think iterators are a good addition, i've started preferring them a lot over regular loops since i started using rust a while back, nice to see them in go, too!
Yeah! I'm really glad theyve prevented them from being used concurrently as well
Great video. I still think the iterators look overly complex, but... you gave really good examples of valid use-cases and it didn't look "that bad". Also, it's not fair that you have such a pleasant voice to listen to haha.
Honestly, I don't understand why so many people were opposed to this feature. It's just a fairly regular implementation of internal iterators (the foreach method found in several languages is an example of an internal iterator).
Despite the fact that I prefer external iterators, this is quite a nice addition to Go.
External iterators are a bit easier to reason about, but are usually slower, since every single iteration is a function call like `iterator.next()`
This is probably the reason why they went with internal iterators, it's a much thinner layer of abstraction on top of a single for loop.
The only real issue I had was that it could be used to obscure concurrency, which I think is something that should always be rather explicit, so I'm really glad it's fixed.
I think for others: Alot of Go users are very protective about the language, mainly because it is incredibly simple, and there's a fear that adding too much might cause it to lose that simplicity.
Go iterators still require function calls (the yield function) to decide whether to continue the iteration or stop. The difference is that the function is implicitly provided by the language. The main problem most people saw with iterators in Go is that the syntax for defining them looks quite alien until you get used to it, and it introduced more "magic" to the language for the machinery that converts a high-order function (the iterator function, which returns a function that takes another function) to the range for loop. As a user, they're quite simple to use, but they're a little awkward to write.
@@maleldil1 Yeah, you're right. In an external iterator every iteration calls a method on the iterator struct, that contains the state of the iteration.
In Go's internal iterators every iteration calls the anonymous function that contains the body of the loop.
So the main difference is that you don't have to define a struct that conforms to some interface, instead you define a function that returns a function that serves the function of an iterator.
That is probably the main source of confusion.
I believe that the prevention of simultaneous loop-body execution was likely because in the original proposal for range-func, the goal was to (eventualy) use coroutines to implement the back and forth between the ranged-over iterator and the range loop (similar to python generators) as an optimization instead of repeatedly calling the yield closure. Coroutines would be passing a single thread of control back and forth, which would completely break if the yield function / loop body could be started multiple times concurrently.
Coroutines aren't the fastest way to implement most loops, as deep inlining would allow the body of the range loop to be inlined into the iterator's push-loop creating a single loop with no additional function calls. However this requires that the iterator and the loop body both be inlineable, and the resulting combination of the two itself be inlinable to have a chance at removing all the layers of abstraction. Instead with coroutines, both the loop body and iterator body can be completely independent with either an indirect (predictable) jump between them in the best case or a more involved but still fast coroutine switch instead of building a new stack frame every iteration.
By putting in the error now, all valid use of range-for shouldn't break the coroutines if/when they are added to the process. They can always remove the restriction later if needed without breaking backwards compatibility. However, doing the reverse, allowing parallel iteration because the closures are safe to call in goroutines would require them to either break any code that relies on that behaviour to use coroutines, or detect when it's not safe and leave the current implementation in place, resulting in vestigial code path(s) to cover the compatibity cases, not to mention the complexity needed in the compiler to statically determine when it's safe to optimize using coroutines.
Coroutines aren't being used for this yet, but the coroutine code does exist (internal to the stdlib/runtime) and is in use to implement iter.Pull/Pull2 to allow one or more pull iterators to be used at the same time without needing goroutines to track the state of each iterator.
As a swifty and crystalist, I don't understand when Go does a fairly minimal, QOL change and the community of developers just kind of lose it. I think Go programmers kind of drink too much in the 'the language should be simple!' kool-aid but ignore how much 'batteries included' the core library has. I would go as far and say that Go is not really as simple as people claim it is.
So is Swift and Swift also has a huge 'batteries included' library. Plus, we all 'need' iterators. It is the most powerful data manipulation tool we have and Golangers were like
"Nope. I will never USE this."
Okay? No one should ask that. I dont use everything in the standard library. It is nothing to something to complain about.
From the pov of Swift and Crystal, then I definitely agree with your conclusion. However, a lot of Go developers come from the viewpoint of Java and C++, which are very complex languages comparatively.
The stdlib of Go is inspired by GlibC and other languages, which is typically much simplier that the stdlib of C++ which can be abhorrent to look at.
As for iterators, I agree, I think they are worthwhile. My only concern was that you could hide concurrency in them, which I'm really glad they've resolved.
I think Swift definitely implements this type of "concurrent custom iterator" more elegantly too. It's at least way easier to read and understand. Like, I can define a custom iterator, but then all of concurrency logic is a separate implementation. IteratorProtocol, Sendable, and AsyncIterator all different protocols to solve different problems.
a make it or break for me in a language are iterator adaptors it just shows the "kind" of language Im getting into
Waooh, this is the first time I have seen the brilliant man behind the scenes .
"Dangerously named 'xiter'"
I agree, it should be pronounced "shitter"... as in Xiaomi :D
Cool techniques. I also found that converting channels to iterators makes APIs much cleaner and user-friendlier.
Nice video, loved the quality for this last videos. What do you think about Golang development team only supporting the last 2 releases, maybe is already time to create an LTS version.
I think with the backwards compatibility support they've added since go 1.22, I'm happy with only supporting the last two releases. I tend to prefer moving fast rather than the alternative (python 2/3 debacle)
I like them, I think, but I'm worried about syntax in Go. It already looks overly verbose, clunky and sometimes unreadable and this piles on another thing on top. Imagine a semi-complex codebase that uses concurrency with channels, is generic and has a function iterator somewhere in the mix. I shudder thinking just how awful this would look.
func Backward[E any](s []E) func(func(int, E) bool) {
return func(yield func(int, E) bool) {
I mean... ugh.
Hi, first of all I loved this video. Could you perhaps make one explaining why this implementation is favored over other implementations? I’m seeing a lot of debate online but I’m interested in learning your take (or perhaps the go team’s take) on why this implementation is favored over others. Thanks :)
I subscribed to your Go course page. Keep on Gooing!
Could they really not have thought of a clearer or more descriptive name than Seq2?
SeqTwo 😭
the fact that there needs to be seperately defined seq and seq2 func for a lot of things is my biggest issue with iterators. but that honestly falls back to a more fundamental lack in go typeing of type unions.
Hey! off topic, but I'm about to pull the trigger on the Keychron V10 Max you reviewed last video. But I had a couple questions - do you need a wristrest for comfortable use? and what was the KB you mentioned in the end of the video - is it substantially better than the keychron in your opinion?
I'm a fan of wrist wrests, mainly because I don't have as good form for typing, so if you're the same the V10 might not be perfect for you.
The keyboard at the end was the ZSA Moonlander, that's currently my favorite keyboard and the one that I use the most at the moment. If you have the budget for it, then I highly recommend it!
feel free to jump on my Discord and ping me if you want some more info.
@@dreamsofcode ❤ Thank you!
Data manipulation is going to be more fun with this new update
I'm not keen on the new iterators.
I'd have liked it if they did it more in the shape of an interface.
PHPs Iterator Interface, for example. That is way easier to understand, than this mess. A mess of functions within functions and some Yields thrown in. It makes things confusing.
All in all, I'm not going to write my own iterators in this way, but I appreciate the option.
Back when Generics were introduced, I too though, that I'd never use them, but there were situations, where they came in handy.
I tried this but I didn't like it much.
I wanted to yield a key & value ( Seq2 ) but also an error as the iterator was fallible.
But, there's no way of doing that.
Could you use a struct for the first value of the Seq2 and then an error for the second value?
Yeah, there seems to be a lack of a way to have a variadic number there. I think it's Go's type system that is starting to bite its own ass.
Laughs in Kotlin
I wanna ask, I have seen your pass video about a password manager and I am really liking it, before I implement it, I wanna ask you if you are still using it, if so that confirms to me that it is reliable. Also any tips about it will be welcomed!
Hey! I'm still using password store, have been since 2018!
@@dreamsofcode Thanks! Love your work, and I really like your videos about convenient tools like this.
@@harunyussuf3593 If you check out my other channel @dreamsofautonomy that focuses more on tooling and configuration!
@@dreamsofcode Yeah I have seen it my config is 80% inspired by you, except I use the terminal emulator kitty. Yours is alacritty right
@@harunyussuf3593 I'm glad to hear that!
Yeah, I'm a full on Alacritty fan. I tend to gravitate towards more simple/minimal tooling.
I just don't get why they did not "simply" used a yield keyword for that.
4:10 x-iter - exciter?
This looks like rust for me, with less features
I don't say ot's bad or good, as all the languages can achieve a working app,, use thame language that you like or the one that,is used by your local businesses
I fear we stray further and further from the kiss principle
why do you wave your hands so much?
is it easier to talk that way?
Swatting flies
The go language is medieval in comparison to others. It gives nothing of value to a modern system devs. Just a hype.The code looks wierd and difficult to suppport
What makes you feel this way?
The compilation time is a huge value, IMHO
@@dreamsofcode i can not state that a struct implements this and this interface. There's no garantee that nobody will change methods contracts. I can not create normal classes with normal methods. I can not override a method. I started to learn go and had found that c# is much better, more universal, and has the same performance. The code is much more clean and clear than the go code.
@@MaximT Implicit interfaces are actually a huge strength in my opinion. It allows you to perform amazing decoupling when used properly. I think I should do a video on it!
@@MaximT So, you're looking to apply C#/Java programming patterns in Go and not write idiomatic Go.