Go Iterators Are Bad

Sdílet
Vložit
  • čas přidán 20. 06. 2024
  • Recorded live on twitch, GET IN
    Article
    www.gingerbill.org/article/20...
    By: x.com/TheGingerBill
    My Stream
    / theprimeagen
    Best Way To Support Me
    Become a backend engineer. Its my favorite site
    boot.dev/?promo=PRIMEYT
    This is also the best way to support me is to support yourself becoming a better backend engineer.
    MY MAIN YT CHANNEL: Has well edited engineering videos
    / theprimeagen
    Discord
    / discord
    Have something for me to read or react to?: / theprimeagenreact
    Kinesis Advantage 360: bit.ly/Prime-Kinesis
    Get production ready SQLite with Turso: turso.tech/deeznuts
  • Věda a technologie

Komentáře • 261

  • @joecairns21
    @joecairns21 Před měsícem +199

    That syntax looks like a nightmare.

    • @mundanesquirrel8687
      @mundanesquirrel8687 Před měsícem +20

      it does. hopefully it'll be hidden away and most of us will mostly consume these, rather than create them.

    • @sillymesilly
      @sillymesilly Před měsícem +11

      And they have the delusion it will replace C.

    • @HypothesisI
      @HypothesisI Před měsícem +5

      A nightmare to implement - not to use. That's basically the only way its justifiable. IMO.

    • @HypothesisI
      @HypothesisI Před měsícem +7

      @@sillymesilly Who? And What? Rust?

    • @linminsu3443
      @linminsu3443 Před měsícem +22

      @@HypothesisIno one said it would replace C. it having a GC to begin with already tells you this lol

  • @BosonCollider
    @BosonCollider Před měsícem +29

    The thing is that Go iterators are primarily there to get people to not use channels for iteration in cases where you just needed an iterator abstraction. So yield just works exactly like "func that pushes into channel" but an order of magnitude faster (yield just calls the loop body instead of going via the goroutine scheduler) and you can refer to shared variables without race conditions.
    If you want a pull based iterator you call iter.Pull on the rangeable func and much like the Go keyword it will create a thread-safe coroutine like in Lua. The approach that Odins creator mentioned here works only for iterating over data structures, but not for usecases like iterating over a database cursor with automatic cleanup at the end, or something nontrivial that actually behaves like a separate process, much like Python generators. The pro and the con of go iterators is that they are goroutines without the overhead of synchronizing across threads.
    Also, the func type signatures will be cleaned up into an alias (1.23 allows parameters in aliases) so that the first line would be
    func Backward[T Any](s []T) Seq[T] {
    ...
    }

    • @defenestrated23
      @defenestrated23 Před měsícem +8

      Ding ding ding. This is the correct answer. The Odin-style iterator works fine for finite data structures (where an "i" makes sense), works less well for a continuous stream (like gRPC streams), poorly for lazy streams/paginators/cursors, and falls on its face where you want to interact with the inner state in any way.
      In python it's the difference between Collection (has len, iter, and next methods), Iterable (has iter and next, but no len), Iterator (has next), and Generator (has next and yield from). The merged proposal can do all of those, the struct iterator can't do it without significant complexity.
      I find the syntax a bit weird but it's tolerable once you spend some time to wrap your head around it.

    • @MartinodF
      @MartinodF Před měsícem

      Thank you for eloquently putting my exact thoughts into words!

  • @jimiscott
    @jimiscott Před měsícem +141

    "When the language you're stann'ng for is still having discussion over iterators." shock.

  • @nesssel
    @nesssel Před měsícem +15

    For anyone still confused, here's an actual explanation of what's going on and where the yield function comes from.
    Go takes your for loop's body and desugars it to a function that takes the loop variables as arguments and processes them. This is what Prime meant how it's similar to a forEach in Javascript.
    If your loop body terminates it returns true so the outer function re-excecutes yield, however a break in the loop body desugars to 'return false' in the function. Similarly continue desugars to an early return of true in the function.
    All that said I strongly feel this should've just been a Ranger interface where these mapping are less obtuse, but range is inherently magical so maybe that's why they didn't care so much.

    • @lazymass
      @lazymass Před měsícem +2

      Damn... I really don't like it...

  • @muno
    @muno Před měsícem +118

    Normally I feel bad about listening to video essays in the background because I feel like I'm missing out on important context. Videos like these alleviate that for me because even if I do watch it I don't understand any of the code onscreen

    • @nyx211
      @nyx211 Před měsícem +18

      It's okay not to look at it even if you do understand it. Golang code looks ugly AF.

    • @Kane0123
      @Kane0123 Před měsícem +23

      @@nyx211I agree. I only look at sexy code.

    • @TOZA
      @TOZA Před měsícem

      ​@@nyx211 nah, golang have one of best looking code I have seen.

    • @MantasXVIII
      @MantasXVIII Před měsícem +8

      Lmao I literally spit my water out reading this.
      Terminally academic people think that if something is complicated, it is to be admired and almost has some universal good.
      I would qoute Terry Davis on this regarding "is this ... or divine intellect" but the glowies would censor me

    • @ts-wo6pp
      @ts-wo6pp Před měsícem +5

      ​​@@MantasXVIIIyou seem weird. Can you try to be more normal?

  • @genuismensa
    @genuismensa Před měsícem +19

    All of the new changes are all for Kubernetes. Every knew K8S version depends on it to the point that they had to delay the deploy of I think it was 1.24 or 1.26 because Go dropped a new version the week before they were going to launch. I listen to the Kubernetes pod cast by Google.

    • @lucascottle2345
      @lucascottle2345 Před 3 dny

      Mind sharing what episode they disscuss this? im interested :)

  • @davidkoffi985
    @davidkoffi985 Před měsícem +61

    I thought go was supposed to be simply? That syntax was so confusing?

    • @enkiimuto1041
      @enkiimuto1041 Před měsícem +4

      I had to pause the video and think about that as soon as I saw it.

    • @7th_CAV_Trooper
      @7th_CAV_Trooper Před měsícem +9

      Skill floor VS skill ceiling.

  • @johanneskohnen8747
    @johanneskohnen8747 Před měsícem +14

    N.b.: „nota bene“ it’s a „Note:“ but with sprinkles

  • @KevinLyda
    @KevinLyda Před měsícem +45

    A go iterator method built off of interfaces and return types would have been clearer.
    So something like this:
    for i, v := iterate (int, string) foo{}
    Where foo meets the interface
    interface{
    Init()
    Next() (int, string)
    }
    Or something like that.

    • @Tvde1
      @Tvde1 Před měsícem

      interface IEnumerable
      {
      T Current;
      bool MoveNext();
      }
      very simple

    • @krumbergify
      @krumbergify Před měsícem +2

      You also need a way to cleanup resources stored in the iterator.

    • @KevinLyda
      @KevinLyda Před měsícem

      @@krumbergify is there some difficulty with adding a third function to the interface?

    • @krumbergify
      @krumbergify Před měsícem +1

      @@KevinLyda No. It’s just that Go in many ways avoids the need to write state machines through its light weight goroutines.
      A worker that reads from a channel, computes a new value and writes it to another channel can be written using a single function without the need for custom structs.
      This iterator design simulates how you would write it using channels although it doesn’t involve concurrency.

    • @michaelthornes
      @michaelthornes Před měsícem +2

      @@krumbergify nitpick: it involves concurrency (interleaving code counts), but doesn't involve parallelism (goroutines/threads)
      > Concurrency is when two or more tasks can start, run, and complete in overlapping time periods. It doesn't necessarily mean they'll ever both be running at the same instant. For example, multitasking on a single-core machine.

  • @albertoarmando6711
    @albertoarmando6711 Před měsícem +15

    I want go to stay as simple as possible.

  • @von_nobody
    @von_nobody Před měsícem +13

    Article author do not understand completely C++ iterators, they do not have `iterator_next()` as they need work for subranges too. This mean you can find two iterators in any range and use them in any place where you could use whole range iterators.
    Another benefits is all algorithms that correctly work with iterators will work with pointers that make range too.

    • @Satook
      @Satook Před měsícem +2

      I reckon Bill probably does understand C++ iterators.
      Having watched and read a few of his blogs and interviews, he’s predisposed towards simplicity and straightforward semantics. So copying C++ anything is likely a non-starter.

    • @egg-mv7ef
      @egg-mv7ef Před 29 dny

      c++ iterators are so gooood

  • @AK-vx4dy
    @AK-vx4dy Před měsícem +5

    I saw once very through presentation on some C++ conference when guy analysed through all kinds of iterators in many languages with pros and cons, very interesting

  • @yapet
    @yapet Před měsícem +5

    This makes me appreciate Lua iterators a lot more.
    Given some similarities between Go and Lua, I think Go would’ve been well-served by the Lua style iterators.
    Although there are things that are dealbreakers as in eyes of Russ: state is not stored in control flow, defer doesn’t really work for cleanup, Lua doesn’t cleanup after iteration ends (which might be fixed by the gingerbill’s onBreak boolean flag)

  • @hanifarroisimukhlis5989
    @hanifarroisimukhlis5989 Před měsícem +15

    That design of iterator also makes it _trivially_ easy to disregard break and possibly leaks the inner closure too. With iterator being struct there's no way for the iterator to know the flow of inner loop at all.

    • @metaltyphoon
      @metaltyphoon Před měsícem +1

      Non sense. In C# you can create iterations that are aware of the loop and is massively simpler. Just introduce a `yield` keyword

    • @Aidiakapi
      @Aidiakapi Před měsícem

      ​@@metaltyphoonC#'s iterators follow an almost identical structure to Rust and Odin, not like Go.
      The yield keyword is just syntactic sugar over top of it which generates the closure and state machine. You can do the same thing in Rust by using generators.

    • @metaltyphoon
      @metaltyphoon Před měsícem

      @@Aidiakapi yes I’m aware of that. I was replying to the OP that C# iterators CAN know about the flow of the inner loop like Go can.

    • @hanifarroisimukhlis5989
      @hanifarroisimukhlis5989 Před měsícem

      @@metaltyphoon I mean, it's more of generators and *not* iterators right? It's not just passing values, but actually influence the inner loop, possibly calling it from *outside* the loop or even other goroutine (which is another huge can of worms).

  • @TheJimeux
    @TheJimeux Před měsícem +7

    I thought I was about to get roasted when I saw my sequence diagram in the thumbnail.
    I’m still not sure how I feel about the iterator spec. There are definitely readability issues, and a type called Seq2 seems more like something from a third-party library. I’m cautiously optimistic though.

  • @genuismensa
    @genuismensa Před měsícem +3

    Return sends a specified value back to its caller whereas Yield can produce a sequence of values. We should use yield when we want to iterate over a sequence, but don’t want to store the entire sequence in memory. Yield is used in Python generators. A generator function is defined just like a normal function, but whenever it needs to generate a value, it does so with the yield keyword rather than return. If the body of a def contains yield, the function automatically becomes a generator function.

    • @sophiophile
      @sophiophile Před měsícem +2

      Also, the main difference from a *practical/performance standpoint* for Python is that when your iterable uses a generator function to instantiate instead of an iterator object, instead of being compiled by loading the entire instance into memory, __next__() calls the function, so it only needs to keep a single value in memory at time.

  • @Bolpat
    @Bolpat Před měsícem +1

    It reminds me of how D does custom iteration. First of all, there are both approaches, i.e. the push and pull approaches. A type that implements the pull approach is called a range. A range has the following members: empty (returns true if it’s done), front (gives you the current element), and popFront (steps forward). A "foreach (x; xs) { … }" is equivalent to "for (auto copy = xs; !copy.empty; copy.popFront) { auto x = copy.front; … }". Most algorithms, such as iota, map, filter, reduce, etc., are based on ranges. However, sometimes iteration needs nontrivial state, such as walking a tree. For that, the push approach is better. In D, you give your type a member function named "opApply", which takes a callback delegate as a parameter. The body of a "foreach" is transformed to an appropriate callback for you. When "opApply" calls the callback, the callback returns 0 indicating "go ahead", or something nonzero, which "opApply" is supposed to return immediately. The transformed foreach body returns non-zero on break, return, goto, etc. (not continue, though). The neat thing is, the D compiler as a switch that lets you see the code after such lowerings.

    • @Bolpat
      @Bolpat Před měsícem

      The opApply can be overloaded with different-arity callbacks so that you can use "foreach (x; xs)", but also "foreach (i, x; xs)" or whatever number of arguments the callback takes.
      I have once written a tree type that has opApply walk the tree and provide an optional index, which is an array of indices that tells you which branch on the respective node was taken. Because "opApply" can re-use the index array, it can be allocated on the stack if the tree height is known in advance.

  • @michaelmueller9635
    @michaelmueller9635 Před měsícem +7

    DUCK SOUND @25:04

  • @blarghblargh
    @blarghblargh Před měsícem +2

    oh are we bringing back the HR cut aways? hell yeah!

  • @JoeTaber
    @JoeTaber Před měsícem +16

    OH the reason why it's not an interface is because Go doesn't support generic interfaces, and may never.

    • @metaltyphoon
      @metaltyphoon Před měsícem +5

      Exactly. Go can’t do genetics methods. Prime has been using Go for a wihile now and can’t seem to have this conclusion

    • @alexlowe2054
      @alexlowe2054 Před měsícem +6

      It's actually sad how many problems are created by the lack of support for genuine generics. Yes, it's slow to compile, but there's a reason most high level strongly typed programming languages support generics. They're super useful for lots of things, and certain problems can't be easily solved without generics. I'm not sure if it's funny or sad how much Go refused to support proper generics.

    • @WoolieOG
      @WoolieOG Před měsícem +1

      wrong, it does support generic interfaces

    • @JoeTaber
      @JoeTaber Před měsícem

      @@WoolieOG Incorrect. Go does not support generic methods on interfaces, which would be required to implement iterators.

    • @JoeTaber
      @JoeTaber Před měsícem

      @@alexlowe2054 It's not a "refuse to support" problem, it's a "nobody came up with a solution that met all the necessary criteria" problem

  • @rayoutube5451
    @rayoutube5451 Před měsícem +2

    The function returning a function isn't a bad approach, but instead of the whole iteration and the yield function stuff, the iterator generator should return a next function like:
    func backwards[T](slice []T) func() (int, T, bool) {
    // setup everything
    return func() (int, T, bool) {
    // backwards access
    }
    }

  • @KalleJillheden
    @KalleJillheden Před měsícem +1

    This Go proposal still allows for vectorization optimizations. I wonder if they could do inlining as well (maybe when doing PGO) of the for loop's code block, which is probably non-trivial as the block is passed around as a function pointer with nested layers of closures.

  • @LaPingvino
    @LaPingvino Před měsícem +2

    I think the reason for this is that for the easy models, Go already has and does what it is supposed to do. The design is literally meant to have full flexibility to implement support for everything else in Go. For anything the simple models support, you can already just use a loop with a channel. Works exactly the way you want and is cheaper. The whole idea of the proposal is to support everything that this approach cannot support.

  • @josefjelinek
    @josefjelinek Před měsícem +13

    This happens in every language which gets wider adoption. Authors somehow lose track what got people attracted in the first place. They suddenly try to accommodate people, which were just force to use the language and do not like it at all.
    This will be used to actually get teams off of Go instead of onboard as the "haters" will just point to this and argue that if you cannot understand it right away, Go is not really as simple as advertised and "we should go with Rust".

    • @hamm8934
      @hamm8934 Před měsícem +6

      How did this get through but arena allocation didnt

    • @josefjelinek
      @josefjelinek Před měsícem +4

      @@hamm8934 a really good question. I know people (who do not hate programming in Go) were waiting for arenas with excitement as it was able to address very real and specific class of performance problems. I know zero people, which were like "I like how Go was doing things so far, but I really want some high-order-functional construct directly in the language, which I will need to relearn every time I want to implement that."

  • @anvityuk
    @anvityuk Před měsícem +1

    I agree that the syntax is not great. However, I disagree with the general statement that pull-based iterators are strictly superior than push-based.
    The beauty of a push-based iterator is that any existing data structure traversal code can be converted to the push-based version. This is almost as simple as replacing your print function with the yield function in relevant places.
    This is not so easy with the push-based, especially if you are using recursion in your implementation. Converting simple recursive algorithm into a pull-based iterator is not that simple.
    Another factor is a performance. In a pull-based version you do end up with more branches since the implementation has to restore its current state on every iteration. This is probably less of an issue for simple traversal algorithms.
    Another problem with the pull-based approach in C++ is that your loop state is managed in different places which makes it harder to reason about loop invariants.
    Where pull-based iterators shine, indeed, is composability. You can easily implement various constructs on top of it, such as iterating two data structures in parallel. This would be impossible in a push-based version without buffering all elements from one of the sides.
    So, back to the Go language proposal. Maybe it is in the spirit of Go’s simplicity.

  • @timburstefan
    @timburstefan Před měsícem

    Hey, Prime, random question: Why i cant watch 4k content on netlfix even if i have the 4k subscription and the HDCP protocol. Is there some sort of limitation because i want to watch 4k netflix content on my 2k screen but i cant so i have to make a custom res of 4k and then check netlfix to see that there is really 4k quality, which it is. Why just cant display 4k content on 2k display just like yt?

  • @SimonBuchanNz
    @SimonBuchanNz Před měsícem +2

    I think the explanation of push vs pull was rather confusing, if not confused.
    Mentioning that JS array methods operate on the whole array before the next method happens is talking about eager vs lazy evaluation, both push and pull iterators can do both - though what Prime is probably getting at here is that it's a lot easier to do eager with a push iterator than lazy, while both are easy with pull.
    The thing named iterator (or enumerator) from you're probably familiar with is a pull iterator, it has some "next" method you call to get either the next value or that it's done. A push interface is the opposite: you pass the iterator a "next" method that receives the items in the control of the iterator.
    The trade-off is generally that pull iterators are much easier to compose, but depending on the language much harder to write (without some sort of generator syntax at least) as they need to keep internal state between calls.
    Push is, in a way, really common in many situations you don't think of as being iterators at all, namely event listeners.

  • @jfftck
    @jfftck Před měsícem +1

    Basic text files are also without a standard for encoding, but a smart user will use UTF-8 and modern software will usually default to it. But before Unicode created a standard, it was very hard to decode text files. Unfortunately, they first created standards that would make every character 2 or more bytes. Because of this, many applications have to have an algorithm to try and determine the encoding.
    So, being surprised that CSV doesn't have an official standard is mostly due to the encoding issue of the file that the data is stored in.

    • @defenestrated23
      @defenestrated23 Před měsícem

      It's worse than that though. CSV makes no claims about when to use quotes or not, LF vs CR vs CRLF, escape characters, illegal sequences, unmatched quoting. Parsers and emitters are basically whatever "feels right"

    • @7th_CAV_Trooper
      @7th_CAV_Trooper Před měsícem

      RFC 4180

  • @blarghblargh
    @blarghblargh Před měsícem +1

    8:30 - "I don't know what n.b. is"
    n.b. is "nota bene", or so FYI. or just "note: ..."

  • @Kane0123
    @Kane0123 Před měsícem +1

    28:05 literally ran into the lack of standard today…

  • @7th_CAV_Trooper
    @7th_CAV_Trooper Před měsícem +1

    Pull VS push. As always it's a tradeoff and depends on the situation. As an architect that's pretty much all I say every day. "maybe. It depends."

  • @KayandraJT
    @KayandraJT Před měsícem +2

    I do agree making go iterators use an interface does make sense.
    fun fact we can sort any arbitrary datastructure in go by fulfilling an interface, so iterators would have fit right into this model.

  • @captainfordo1
    @captainfordo1 Před měsícem +3

    Odin mentioned.

  • @escher4401
    @escher4401 Před měsícem

    That's a pretty standard generator/coroutine/callback of callback/observer of observer pattern, it's just in the functional syntax

  • @0xdiane
    @0xdiane Před měsícem +2

    I don’t have time to watch the full video so I might be missing context, but it seems really strange to me that channel syntax and go routine syntax wasn’t used. Really there’s not much going on here aside from having a go routine and channel that can swap back and forth without hitting a scheduler / mutex. Could have the syntax be like, out := go func(){ out

    • @defenestrated23
      @defenestrated23 Před měsícem

      One of the main points was performance, because folks were using channels for iterator-like behavior. Channels have a mutex and involve the scheduler. Iterators are pure function calls and have order of magnitude less overhead.

  • @sungwoolee484
    @sungwoolee484 Před měsícem

    I expected a reaction video, prime.

  • @doppeltevier
    @doppeltevier Před měsícem

    Could you create a video about Atlassian's new framework-agnostic, low-level dnd library called "pragmatic-drag-and-drop"?

  • @faiqr
    @faiqr Před měsícem

    they should have just called it yeet

  • @thekwoka4707
    @thekwoka4707 Před měsícem

    the iterator syntax, while it has sense to it, looks like pure chaos.
    the whole function that returns a function that returns a function makes it look quite awkward.

  • @dorktales254
    @dorktales254 Před měsícem +2

    I guess we can call them "shiterators"

  • @ThomasWSmith-wm5xn
    @ThomasWSmith-wm5xn Před měsícem +1

    what the heck - i dont re-write the stuff ; i use proper golang structure so if i have it one place i can use it anywhere.

  • @KevinLyda
    @KevinLyda Před měsícem

    I do wish they'd used an interface for iterators.

  • @patrickshepherd1341
    @patrickshepherd1341 Před 16 dny

    Lol do you think Dijkstra ever imagined that one article title would come to be a built in joke for programmers? 18:28

  • @batatanna
    @batatanna Před měsícem

    It's been a while I've felt dumb watching a CS video. Guess I have to study more iterators.

  • @xhivo97
    @xhivo97 Před měsícem +1

    I love gingerbill I will watch this.

  • @KangoV
    @KangoV Před měsícem

    To parse CSV I use an ANTLR grammer/lexer/parser. It's so cool.

  • @chaoslab
    @chaoslab Před měsícem

    Tonight on "When Iterators Go Bad!" (I'll show myself out...)

  • @TravisBerthelot
    @TravisBerthelot Před měsícem

    Iterators perform poorly in C++ and Java as well. In what language are iterators a good thing (does not create objects)?

  • @batboy49
    @batboy49 Před měsícem

    I thought I would hate it....I love it now.

  • @Alguem387
    @Alguem387 Před měsícem +1

    Closures are just fancy objects, functions that take functions and return functions are just fancy classes

    • @7th_CAV_Trooper
      @7th_CAV_Trooper Před měsícem

      You're saying a closure is a higher order function? That's not right.

  • @biggerdoofus
    @biggerdoofus Před měsícem +3

    I use c and lua because I like small numbers of tool rather large toolboxes. Do I get to be mediocre too?

  • @microcolonel
    @microcolonel Před měsícem +1

    In JavaScript you have push and pull, as well as both generators and a method interface. I think it's a'ight.

  • @luizpbraga
    @luizpbraga Před měsícem

    "I'm a language designer" 6:30

  • @megetmorsomt
    @megetmorsomt Před měsícem

    Nim:
    iterator reversed[T](x:openArray[T]):T =
    var idx = x.high
    while idx >= x.low:
    yield x[idx]
    dec idx
    var nrs = [1,2,3,4,5,6,7,8,9,10]
    for nr in reversed nrs:
    echo nr

  • @krumbergify
    @krumbergify Před měsícem +1

    I really like that the new iterators in Go support defer.

  • @blarghblargh
    @blarghblargh Před měsícem

    I haven't thought about it much, but does "the odin iterator approach" require that each slice be fully baked out into contiguous memory, or can it deal with sparse generation/population? cause I think other iterator approaches might be more generalizable.
    is that difference the difference between "push" and "pull" iterators? I haven't heard those terms before.
    not sure how much that matters in practice. I have used iterators and made generators a decent amount (about a decade), and I understand the state machine under the covers, but I haven't thought comparatively about different approaches to implementing them. in places where I've actually cared about performance, I've switched to a fully imperative model that's as stupid and ugly as possible, so I could be damned sure of the memory usage and control flow patterns.
    but now that the subject is coming up, would be interested to see the differences.

    • @michaelthornes
      @michaelthornes Před měsícem

      summarizing a top-level comment here from SimonBuschanNz about push vs pull:
      push iterators are in control of the data, and are easier to implement (ie loop over data and yield values), but do require that ability to yield values. push iterators are like event emitters or js .forEach, where the iterator controls the data and you pass it the next function, so it can call that with each element.
      pull iterators can be more difficult to implement, because they usually need to keep state, but they can be easier to use on the client side. pull iterators are like calling a next function on the iterator when you want the next value, but you can choose to stop, skip by ignoring, sometimes reverse, etc. whenever you want.
      generators by means of go channels are push model, the iterator produces data on its terms. generators in js are pull model, since you have to explicitly ask for values by calling next on the iterator (js does allow you to "push" values by using yield. however, generators don't choose *when* the client code runs, since they don't call a function which runs the content of the loop like .forEach doesz the caller chooses when, if ever, to accept the produced yield values, by calling next)
      if you want to iterate over an infinite resource, like an iterator which always produces 0, you generally want a pull iterator, unless you're given a way to stop a push iterator (like your callback returning true/false) or you want it to go on forever

    • @marcsfeh
      @marcsfeh Před měsícem

      the Odin style is literally just a function + struct. There's nothing else to it, I made odin iterators in my text editor back when I used a tree like data structure and it works fine. It might be less pretty upfront but it's zero-magic. It's just a function that returns values + a bool.

  • @jessypouliot8374
    @jessypouliot8374 Před měsícem +1

    n.b. "nota bean" did chat meant to say "notez bien" 🇫🇷. Wtf is a naughty bean

    • @bitmasked
      @bitmasked Před měsícem +1

      It's from the latin "nota bene". On a beau être géniaux, on n'est pas le centre du monde.

  • @miracleinnocent2649
    @miracleinnocent2649 Před měsícem +1

    we really need to gate keep more

  • @LeetHaxington
    @LeetHaxington Před měsícem

    Chat plays Go

  • @microcolonel
    @microcolonel Před měsícem

    Both generators and first class async are almost the same thing: a persistent scope/continuation.
    If they made this thing a single concept from the language side, that would be one thing...
    Generators are great, can be a lot cleaner than struct (because the struct IS the scope), but the way they designed it for Go doesn't make sense to me.

  • @ThomasWSmith-wm5xn
    @ThomasWSmith-wm5xn Před měsícem +1

    hate the go iterators; javascripting my golang with worse looking syntax.

  • @krumbergify
    @krumbergify Před měsícem

    CSV tried to be so simple that it became extremly complicated.

  • @ddystopia8091
    @ddystopia8091 Před měsícem

    Rust also has yield etc, called coroutines (generators previously)

  • @jakubtomsu
    @jakubtomsu Před měsícem +1

    ODIN MENTIONED!!!🔥 WTF IS A BAD LANGUAGE DESIGN 🗣️🗣️

  • @_neophyte
    @_neophyte Před 7 dny

    5P and LTTM seething rn

  • @gh5777
    @gh5777 Před měsícem

    C++ mentioned

  • @FUBAU
    @FUBAU Před měsícem

    I did honestly enjoy this video, as I generally dislike the screaming and acting “for entertainment/show”. Thanks!

  • @larjasoul
    @larjasoul Před 18 dny

    My issue is: what does this let Go do that it couldn't before? This is a violation of what most people like about Go.

  • @bokunochannel84207
    @bokunochannel84207 Před měsícem

    compared to other changes in GO (everything isn't internal), iterator involve very little ammount of go contributors and i think their decision are biased.
    "if you can't decide, the answer is no."
    they shoudn't standarize iterator. but instead provide a best practive guides.

  • @Lars-ce4rd
    @Lars-ce4rd Před měsícem

    yeah, so who are we going to believe? The mighty creator Thor, or the guy trying to convince us of his cgi stach?

  • @PassifloraCerulea
    @PassifloraCerulea Před měsícem

    I'd have more sympathy for Rob Pike's statement about Googlers not being able to appreciate a brilliant language if I knew of a brilliant language he himself had designed earlier. As it is, it feel like several of Go's design deficiencies have more to do with Pike and team's unfamiliarity with non-C-family language features. For example, in ML sum types & pattern matching and type inference & generics work together brilliantly but it's still plenty simple to learn and use.
    I appreciate Go's simplicity, but I can't shake the notion that it would have been a much better language while only a tiny bit more complex if it had some of these features, and further that if they had been familiar ML or similar that it wouldn't have taken them a decade to figure out how to do generics.

  • @johnhershberg5915
    @johnhershberg5915 Před měsícem +27

    Every time I hear Prime describe what a language should be I think he's describing C#. You can't make a language so simple that people need to write everything every time, you need to make a language simple enough so everything you need to write should already be written and provided in the standard library. That's C# and .NET!

    • @jimiscott
      @jimiscott Před měsícem +14

      I bet he writes c# all the time, but doesn't have the guts to tell us.

    • @infantfrontender6131
      @infantfrontender6131 Před měsícem +1

      @@jimiscott, literally C# tsundere-kun

    • @Jason-xw2md
      @Jason-xw2md Před měsícem +7

      besides errors as values, and null safety o_O

    • @johnhershberg5915
      @johnhershberg5915 Před měsícem

      @@Jason-xw2md You can do errors as values if you want.
      What do you mean by null safety?

    • @zwparchman
      @zwparchman Před měsícem +8

      ​@@johnhershberg5915
      You cannot as the code you call is free to throw exceptions. You can do a mix, but that isn't the same.

  • @Jojor11
    @Jojor11 Před měsícem +8

    When I tested go, I felt like the things I missed were generics and iterators… it feels like I’ll be completely happy with go soon xd

    • @AdroSlice
      @AdroSlice Před měsícem +1

      Honestly the only thing that's missing for me is an easier way to deal with common errors. Zig does this excellently by implementing error returns as a seperate language construct rather than using multiple returns, which allowed them to easily implement operators to early return errors

    • @natescode
      @natescode Před měsícem +4

      So basically when Go catches up to real languages but with worse developer ergonomics.

    • @orterves
      @orterves Před měsícem +1

      Except they both seem half-baked and tacked on

  • @lovyNOM
    @lovyNOM Před měsícem +7

    imo I prefer C# iterators, they keywords yield return and yield break (and other syntax sugar) make it's iterators easy to read

    • @101Mant
      @101Mant Před měsícem +1

      Very similar to Python iterators and other languages.
      Go seems to have made an overly complicated mess of a problem that has been clearly solved already.

    • @sophiophile
      @sophiophile Před měsícem

      ​@@101Mant Yeah, things like the simplicity of having an iterator that is not an iterable, simply by using a generator function/using a yield statement so that you don't have to load iterables that are unfeasibly large, while having to change *nothing* else, is a perfect example of why I just zone out all the hate Python gets and finish POC projects 10x faster than other teams. Haha.

    • @SimonBuchanNz
      @SimonBuchanNz Před měsícem

      That's generators, strictly: a way to implement the iterator interface. (Actually IEnumerable/IEnumarator)
      Iterators are more about having an easy way to consume sequences (for each) than to define them, but really you want both.

    • @sophiophile
      @sophiophile Před měsícem

      @@SimonBuchanNz At least in Python's parlance, an iterator is a built-in class that takes either:
      * an iterable (an object, like a list, tuple, etc) which is iterated over, calling __next__() after each iteration to retrieve the subsequent item in it, or
      * a generator (a function that ends with a yield statement, and each time __next__() is called the function is called again to generate the next term in the sequence instead of loading a whole iterable when the class is constructed)

    • @SimonBuchanNz
      @SimonBuchanNz Před měsícem

      @@sophiophile that makes __next__ the python iterator interface, so a generator is still an iterator.

  • @alexischicoine2072
    @alexischicoine2072 Před měsícem

    The whole point of csv is that there’s no standard and it’s free for all.
    In the end it usually works fine other than it’s very slow.

  • @andrewzuo86
    @andrewzuo86 Před měsícem +1

    What's wrong with CSV? Although TSV is better because you're less likely to use tabs.

    • @maccsguitar
      @maccsguitar Před 14 dny +1

      That its a non-standard brings problems everywhere. Some are separated with a comma, some are separated with semicolons or tabs, some have quotes surrounding the values and some have them only when the separator is included in the value, some use haphazard json-typing inside the values, some have more than one header-row and so produce multiple tables, some allow newlines inside values, some use backslash for escaping and some don't, some programs produce a different syntax depending on locale and don't know how to read all of their own produced formats (e.g. excel). Standardization would do it good.

  • @alexpyattaev
    @alexpyattaev Před měsícem +3

    Any iterator ultimately stores state, rust just makes it explicit. The downside of this in rust is that it requires lifetems which are unfun. In go it would have been so easy to do with no additional syntax.

  • @klasus2344
    @klasus2344 Před měsícem

    If the language itself is powerful enough (like Rust), iterators are a cake walk

  • @recarsion
    @recarsion Před měsícem +1

    This just feels so unneeded to me ngl. The whole selling point of Go is being a grug-brained language and this is the opposite of that.

  • @TheCatmorte
    @TheCatmorte Před měsícem

    Same for me. It butthurted me so much right after announcement. We were ok without it and now instead of well known N approaches of doing things we'll have N+1 approach. Already imagining zoomers and boomers arguing in the comments under every PR about doing/not doing sht though iterators

  • @realms4219
    @realms4219 Před měsícem +12

    The most important aspect of a language is readability. This seems extremely unpleasant to process mentally, like Rust.

    • @porcupinetree-bb3zg
      @porcupinetree-bb3zg Před měsícem +13

      rust is more readable than go in my opinion. it's kind of a combination of javascript and ocaml syntax which i find to be readable. in theory go should be more readable but it requires a lot of boilerplate and i find boilerplate in go to be ugly and hard to read.

    • @monolith-zl4qt
      @monolith-zl4qt Před měsícem +3

      @@porcupinetree-bb3zg as a beginner in Go, I have no problem understanding any codebase, idk what unreadable boilerplate you're talking about. Go is by far the most readable lang I've used, but then again I've never touched rust so far. But what I hear from others about Rust is everything but a nice readability experience

    • @natescode
      @natescode Před měsícem +5

      Less code is more readable that the mess that Go is becoming. Maybe true for junior engineers.

  • @Gennys
    @Gennys Před měsícem +26

    In my mind, whenever Prime says "I wish they would have done it the *Rust* way". I can almost always just replace Rust with Java and it still works. Because he's usually just talking about interfaces anyway xD.

    • @tempname8263
      @tempname8263 Před měsícem

      If you can replace it with Java, then you can replace it with C#. If you can replace it with C#, then you can replace it with BeefLang, - the ultimate language of all programming 🐮

  • @paxcoder
    @paxcoder Před měsícem

    The author admits himself to be imperative programming oriented. I think this is why the imperative variant looks easier to him. To me, the variant with yield is more straightforwards, maybe because I went through a functional programming (learning) phase. With functional programming concepts being built-into languages these days, I think new coders might agree

  • @mrdmajor
    @mrdmajor Před měsícem

    Watching programmers argue, complain and make memes over complex unreadable syntax and calling human readable syntax "lame" is bizarre. I don't ever want to be a "programmer", I just want to learn how to create solutions for things I personally need done. I'd rather be on the Evan Czaplicki or Richard Feldman side of things. Thanks for reminding me why, genius system/low-level programmers. 🤣✌

  • @IgorKaratayev
    @IgorKaratayev Před měsícem +5

    Go iterators are very simple, people just overcomplicate them in their mind for some reason.

  • @nikocarpenter
    @nikocarpenter Před měsícem +2

    There's a reason Go couldn't implement pull iterators with an interface. Something like
    type Iterable[T any] {
    Iter() Iterator[T]
    }
    type Iterator[T any] {
    Next() (T, bool)
    }
    Seems like a very nice interface. The problem, and this was called out, is what if someone defines a type like `type MyType chan int`, and then implements Iterable on MyType? Now, if you for range over an instance of MyType, it's unclear as to whether you should get an iterator and call it's Next method, or whether you should receive values from the channel.
    By making both push and pull iterators functions, you're making them unique types, rather than existing types that implement an interface, so this problem goes away.

    • @nullid1492
      @nullid1492 Před měsícem

      Just prevent implementing the iterator interface on channels. This is the same as how in rust you cannot impl iterator on the Range struct or any other struct that is already iterable.
      A neat way of doing this is to make a channel internally use the iterator interface.

    • @TurtleKwitty
      @TurtleKwitty Před měsícem

      If MyType implements the Iterable then clearly they meant to by iterable on MyType? Not sure how that would be unclear

  • @simonplace5164
    @simonplace5164 Před 10 dny

    @0:42 "for key,value := range myStruct" is 'super cool feature' only problem => it doesn't exist!
    thought i might have missed so double checked and everything. (during which i see others saying this.)WTF
    FWIW here's an field iter...
    '''
    import "reflect"
    func Fields(v any) (seq[struct{string;any}]){
    values := reflect.ValueOf(v)
    types := values.Type()
    return func(on func(struct{string;any})bool){
    for i := 0; i < values.NumField(); i++ {
    if !on(struct{string;any}{types.Field(i).Name,values.Field(i).Interface()}){
    return
    }
    }
    }
    }
    '''

  • @TheHackysack
    @TheHackysack Před měsícem

    Please fix your "STREAM" link in your description.

  • @justintie
    @justintie Před 4 dny

    yes, for sure

  • @Tvde1
    @Tvde1 Před měsícem

    why make such complex concepts and such heavy and complex function definitions (you have to write func 6 times) instead of making it simple like C#

  • @TheWrxrally
    @TheWrxrally Před měsícem

    They tried to make it look like Python generators. That's the easiest way to think about it if you know Python.

  • @leonscander1431
    @leonscander1431 Před 24 dny

    Are there any chances the Go dev team will change their mind and not introduce this horrible iterator concept in 1.23?

  • @tiko-
    @tiko- Před měsícem

    they are good actually. i've written like 5 slightly different iterators when making libraries. just give me a standard interface. thank you

  • @Karurosagu
    @Karurosagu Před měsícem

    bro what the func
    i thought go was supposed to be simple

  • @bopon4090
    @bopon4090 Před měsícem

    i mean go is easy to use and learn but hard to master.

  • @CakeIsALie99
    @CakeIsALie99 Před měsícem

    Python generator(iterator) syntax makes it so easy to use. Yes its fun to shit on python for being slow and having a shitty type system but some of the other features could inspire other langs

  • @Tigregalis
    @Tigregalis Před měsícem +1

    Rust unironically has far cleaner syntax than this mess.

  • @rosehogenson1398
    @rosehogenson1398 Před měsícem +1

    I like go a lot, and honestly I think they managed to find a solution that is very much in the spirit of go's simplicity. Like so much of the language, it requires a little bit more verbosity from the programmer, but it's clear what's happening under the hood.

  • @skeleton_craftGaming
    @skeleton_craftGaming Před měsícem

    15:29 yes writing LUA is easy but writing the interface between Lua and your C[++] program is not...
    I don't think that C++ iterators are the same thing as go/Odin iterators... C++ iterators are an abstraction of pure pointer math were as it seems that in GO and Odin they seem to generators incrementing over a list... and for what its worth c++ is like 40 years old at this point ...

    • @shinjoshinjo946
      @shinjoshinjo946 Před měsícem

      Oh thanks for pointing that out. My only exposure to iterators so far has been in the context of C++ STL where they are explained as an abstraction of pointer arithmetic for custom data structures. So if you have proper operator overloading for your iterator type which conforms to the STL interface, an STL algo can operate on the elements without being exposed to its implementation details. While in Go iterators are more discussed in the context of iterating over a collection one element at a time, thereby saving memory, and also generators

    • @skeleton_craftGaming
      @skeleton_craftGaming Před měsícem

      @@shinjoshinjo946 C++'s iterators are pointers that point to the next value in the container rather than in the the next valid address for the contained T. AS FAR I CAN TELL Odin and GO just abstract the whole pointer thing away (so it is just opaque copy)

  • @Tony-dp1rl
    @Tony-dp1rl Před měsícem

    I will never understand why Go has such terrible syntax. It was freaking new. Everything the language is designed to do could have been done with really nice, familiar syntax, and it would have been an amazing language.

    • @marcsfeh
      @marcsfeh Před měsícem

      what do you mean by familiar syntax? the horrible context-dependent mess that is C and all languages that got inspired by its syntax? it's great that Go chose correctness over developers' highly subjective and quite frankly wrong taste.