Go Iterators Are Bad

Поделиться
HTML-код
  • Опубликовано: 11 сен 2024
  • Recorded live on twitch, GET IN
    Article
    www.gingerbill...
    By: x.com/TheGinge...
    My Stream
    / theprimeagen
    Best Way To Support Me
    Become a backend engineer. Its my favorite site
    boot.dev/?prom...
    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-K...
    Get production ready SQLite with Turso: turso.tech/dee...

Комментарии • 271

  • @BosonCollider
    @BosonCollider 2 месяца назад +37

    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 2 месяца назад +11

      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 2 месяца назад

      Thank you for eloquently putting my exact thoughts into words!

  • @joecairns21
    @joecairns21 2 месяца назад +227

    That syntax looks like a nightmare.

    • @mundanesquirrel8687
      @mundanesquirrel8687 2 месяца назад +21

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

    • @sillymesilly
      @sillymesilly 2 месяца назад +12

      And they have the delusion it will replace C.

    • @HypothesisI
      @HypothesisI 2 месяца назад +6

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

    • @HypothesisI
      @HypothesisI 2 месяца назад +7

      @@sillymesilly Who? And What? Rust?

    • @linminsu3443
      @linminsu3443 2 месяца назад +24

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

  • @jimiscott
    @jimiscott 2 месяца назад +155

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

  • @nesssel
    @nesssel 2 месяца назад +16

    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 2 месяца назад +2

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

  • @muno
    @muno 2 месяца назад +128

    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 2 месяца назад +19

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

    • @Kane0123
      @Kane0123 2 месяца назад +24

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

    • @TOZA
      @TOZA 2 месяца назад

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

    • @MantasXVIII
      @MantasXVIII 2 месяца назад +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 2 месяца назад +7

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

  • @genuismensa
    @genuismensa 2 месяца назад +20

    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 Месяц назад

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

  • @davidkoffi985
    @davidkoffi985 2 месяца назад +65

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

    • @enkiimuto1041
      @enkiimuto1041 2 месяца назад +4

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

    • @7th_CAV_Trooper
      @7th_CAV_Trooper 2 месяца назад +11

      Skill floor VS skill ceiling.

    • @iatheman
      @iatheman Месяц назад +1

      @@7th_CAV_Trooper With go the height wasn't very high and the house was build at sea level. Now its still at sea level but the ceiling is higher.

  • @KevinLyda
    @KevinLyda 2 месяца назад +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 2 месяца назад

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

    • @krumbergify
      @krumbergify 2 месяца назад +2

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

    • @KevinLyda
      @KevinLyda 2 месяца назад

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

    • @krumbergify
      @krumbergify 2 месяца назад +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 2 месяца назад +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.

  • @johanneskohnen8747
    @johanneskohnen8747 2 месяца назад +14

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

  • @von_nobody
    @von_nobody 2 месяца назад +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 2 месяца назад +4

      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 2 месяца назад

      c++ iterators are so gooood

  • @JoeTaber
    @JoeTaber 2 месяца назад +18

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

    • @metaltyphoon
      @metaltyphoon 2 месяца назад +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 2 месяца назад +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 2 месяца назад +1

      wrong, it does support generic interfaces

    • @JoeTaber
      @JoeTaber 2 месяца назад

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

    • @JoeTaber
      @JoeTaber 2 месяца назад

      @@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

  • @hanifarroisimukhlis5989
    @hanifarroisimukhlis5989 2 месяца назад +17

    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 2 месяца назад +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 2 месяца назад

      ​@@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 2 месяца назад

      @@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 2 месяца назад

      @@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).

  • @yapet
    @yapet 2 месяца назад +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)

  • @TheJimeux
    @TheJimeux 2 месяца назад +8

    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.

  • @AK-vx4dy
    @AK-vx4dy 2 месяца назад +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

  • @josefjelinek
    @josefjelinek 2 месяца назад +14

    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 2 месяца назад +6

      How did this get through but arena allocation didnt

    • @josefjelinek
      @josefjelinek 2 месяца назад +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."

  • @genuismensa
    @genuismensa 2 месяца назад +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 2 месяца назад +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.

  • @johnhershberg5915
    @johnhershberg5915 2 месяца назад +28

    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 2 месяца назад +14

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

    • @infantfrontender6131
      @infantfrontender6131 2 месяца назад +1

      @@jimiscott, literally C# tsundere-kun

    • @Jason-xw2md
      @Jason-xw2md 2 месяца назад +7

      besides errors as values, and null safety o_O

    • @johnhershberg5915
      @johnhershberg5915 2 месяца назад

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

    • @zwparchman
      @zwparchman 2 месяца назад +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.

  • @rayoutube5451
    @rayoutube5451 2 месяца назад +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
    }
    }

  • @Bolpat
    @Bolpat 2 месяца назад +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 2 месяца назад

      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.

  • @LaPingvino
    @LaPingvino 2 месяца назад +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.

  • @anvityuk
    @anvityuk 2 месяца назад +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.

  • @SimonBuchanNz
    @SimonBuchanNz 2 месяца назад +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.

  • @albertoarmando6711
    @albertoarmando6711 2 месяца назад +16

    I want go to stay as simple as possible.

  • @blarghblargh
    @blarghblargh 2 месяца назад +2

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

  • @michaelmueller9635
    @michaelmueller9635 2 месяца назад +7

    DUCK SOUND @25:04

  • @Gennys
    @Gennys 2 месяца назад +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 2 месяца назад

      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 🐮

  • @realms4219
    @realms4219 2 месяца назад +12

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

    • @matress-4-2323
      @matress-4-2323 2 месяца назад +14

      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 2 месяца назад +3

      @@matress-4-2323 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 2 месяца назад +6

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

  • @KalleJillheden
    @KalleJillheden 2 месяца назад +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.

  • @blarghblargh
    @blarghblargh 2 месяца назад +2

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

  • @jfftck
    @jfftck 2 месяца назад +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 2 месяца назад

      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 2 месяца назад

      RFC 4180

  • @7th_CAV_Trooper
    @7th_CAV_Trooper 2 месяца назад +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 2 месяца назад +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.

  • @lovyNOM
    @lovyNOM 2 месяца назад +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 2 месяца назад +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 2 месяца назад

      ​@@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 2 месяца назад

      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 2 месяца назад

      @@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 2 месяца назад

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

  • @ThomasWSmith-wm5xn
    @ThomasWSmith-wm5xn 2 месяца назад +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.

  • @0xdiane
    @0xdiane 2 месяца назад +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 2 месяца назад

      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.

  • @IgorKaratayev
    @IgorKaratayev 2 месяца назад +5

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

  • @Kane0123
    @Kane0123 2 месяца назад +1

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

  • @TravisBerthelot
    @TravisBerthelot 2 месяца назад

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

  • @captainfordo1
    @captainfordo1 2 месяца назад +3

    Odin mentioned.

  • @alexpyattaev
    @alexpyattaev 2 месяца назад +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.

  • @megetmorsomt
    @megetmorsomt 2 месяца назад

    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

  • @escher4401
    @escher4401 2 месяца назад

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

  • @isodoubIet
    @isodoubIet 2 месяца назад +8

    "historically, a C++ iterator would look like this:"
    *shows a snippet of what range-for desugars to*
    So much for the language designer.

    • @isodoubIet
      @isodoubIet 2 месяца назад +4

      Dude also has no idea why C++ iterators work the way they do. Anyone who wants to _actually_ understand this stuff and the tradeoffs being made should watch the talk "Iterators and Ranges: Comparing C++ to D to Rust" by Barry Revzin.

    • @qqshutup7175
      @qqshutup7175 2 месяца назад +1

      @@isodoubIet exactly, every time they need to compare how c++ handles this, they show how the expression is defined behind the compiler and not how it's actually used, it says a lot about the person...
      "hey, let's compare it to c++"
      - put the "real" c++ code in cppinsights and show the code to the compiler's eyes

    • @justanothercomment416
      @justanothercomment416 2 месяца назад +2

      And the standard library is so complete it's extremely unlikely you'll ever need to write an iterator in C++. So his entire argument is rather moot.

    • @loo_9
      @loo_9 2 месяца назад

      @@isodoubIetgiving this a watch, thx

    • @isodoubIet
      @isodoubIet 2 месяца назад +1

      @@justanothercomment416 And if you do end up having to write your own, it will automatically work correctly with all the algorithms in the standard library, some of which are flat out impossible to write in simpler iterator models. Alex Stepanov's STL is a work of genius; anyone trying to criticize it should at the very least understand it.

  • @timburstefan
    @timburstefan 2 месяца назад

    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?

  • @thekwoka4707
    @thekwoka4707 2 месяца назад

    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.

  • @nikocarpenter
    @nikocarpenter 2 месяца назад +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 2 месяца назад

      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 2 месяца назад

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

  • @Alguem387
    @Alguem387 2 месяца назад +1

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

    • @7th_CAV_Trooper
      @7th_CAV_Trooper 2 месяца назад

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

  • @microcolonel
    @microcolonel 2 месяца назад

    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.

  • @Jojor11
    @Jojor11 2 месяца назад +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 2 месяца назад +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 2 месяца назад +6

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

    • @orterves
      @orterves 2 месяца назад +1

      Except they both seem half-baked and tacked on

  • @biggerdoofus
    @biggerdoofus 2 месяца назад +3

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

  • @bokunochannel84207
    @bokunochannel84207 2 месяца назад

    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.

  • @dorktales254
    @dorktales254 2 месяца назад +2

    I guess we can call them "shiterators"

  • @patrickshepherd1341
    @patrickshepherd1341 Месяц назад

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

  • @microcolonel
    @microcolonel 2 месяца назад +1

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

  • @alexischicoine2072
    @alexischicoine2072 2 месяца назад

    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.

  • @krumbergify
    @krumbergify 2 месяца назад +1

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

  • @jakubtomsu
    @jakubtomsu 2 месяца назад +1

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

  • @ThomasWSmith-wm5xn
    @ThomasWSmith-wm5xn 2 месяца назад +1

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

  • @larjasoul
    @larjasoul Месяц назад

    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.

  • @recarsion
    @recarsion 2 месяца назад +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.

  • @doppeltevier
    @doppeltevier 2 месяца назад

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

  • @andrewzuo86
    @andrewzuo86 2 месяца назад +1

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

    • @maccsguitar
      @maccsguitar Месяц назад +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.

  • @miracleinnocent2649
    @miracleinnocent2649 2 месяца назад +1

    we really need to gate keep more

  • @paxcoder
    @paxcoder 2 месяца назад

    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

  • @PassifloraCerulea
    @PassifloraCerulea 2 месяца назад

    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.

  • @chaoslab
    @chaoslab 2 месяца назад

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

  • @klasus2344
    @klasus2344 2 месяца назад

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

  • @FUBAU
    @FUBAU 2 месяца назад

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

  • @faiqr
    @faiqr 2 месяца назад

    they should have just called it yeet

  • @NatoBoram
    @NatoBoram 2 месяца назад +1

    ... I feel like it's not really an iterator if it's not a pull iterator...
    At that point, why not just `.map()` or `for index` over it?
    Lazy iterators can be wrapped by another iterator and you can end up with something extremely efficient

  • @batboy49
    @batboy49 2 месяца назад

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

  • @jessypouliot8374
    @jessypouliot8374 2 месяца назад +1

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

    • @bitmasked
      @bitmasked 2 месяца назад +1

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

  • @blarghblargh
    @blarghblargh 2 месяца назад

    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 2 месяца назад

      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 2 месяца назад

      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.

  • @mikhailryzhov9419
    @mikhailryzhov9419 Месяц назад

    CSV is for people who don't like regulation, you can make your own rules and carve your own incompatible path.

  • @mrdmajor
    @mrdmajor 2 месяца назад

    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. 🤣✌

  • @KevinLyda
    @KevinLyda 2 месяца назад

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

  • @dough-pizza
    @dough-pizza 2 месяца назад

    Just code in a normal language like Java guys, that go snippet was simply too horrible to deal with

  • @TheCatmorte
    @TheCatmorte 2 месяца назад

    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

  • @Lars-ce4rd
    @Lars-ce4rd 2 месяца назад

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

  • @batatanna
    @batatanna 2 месяца назад

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

  • @TheWrxrally
    @TheWrxrally 2 месяца назад

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

  • @krumbergify
    @krumbergify 2 месяца назад

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

  • @luizpbraga
    @luizpbraga 2 месяца назад

    "I'm a language designer" 6:30

  • @xhivo97
    @xhivo97 2 месяца назад +1

    I love gingerbill I will watch this.

  • @Tvde1
    @Tvde1 2 месяца назад

    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#

  • @_neophyte
    @_neophyte Месяц назад

    5P and LTTM seething rn

  • @rosehogenson1398
    @rosehogenson1398 2 месяца назад +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.

    • @dough-pizza
      @dough-pizza 2 месяца назад

      That's the same cope Java devs use but atleast Java is actually readable

  • @KangoV
    @KangoV 2 месяца назад

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

  • @tiko-
    @tiko- 2 месяца назад

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

  • @Tigregalis
    @Tigregalis 2 месяца назад +1

    Rust unironically has far cleaner syntax than this mess.

  • @sungwoolee484
    @sungwoolee484 2 месяца назад

    I expected a reaction video, prime.

  • @bopon4090
    @bopon4090 2 месяца назад

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

  • @TheHackysack
    @TheHackysack 2 месяца назад

    Please fix your "STREAM" link in your description.

  • @Tony-dp1rl
    @Tony-dp1rl 2 месяца назад

    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 2 месяца назад

      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.

  • @gh5777
    @gh5777 2 месяца назад

    C++ mentioned

  • @ddystopia8091
    @ddystopia8091 2 месяца назад

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

    • @SimonBuchanNz
      @SimonBuchanNz 2 месяца назад +1

      Nothing is real until it's stable

  • @simonplace5164
    @simonplace5164 Месяц назад

    @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
    }
    }
    }
    }
    '''

  • @badrakhariunchimeg1031
    @badrakhariunchimeg1031 Месяц назад

    Don't they have ssh of their own for example reg 0110++1 mov reg [massage] ;

  • @zactron1997
    @zactron1997 2 месяца назад

    I despise this version of Go iterators. Far too hard to understand what's going on at a glance and very deeply nested. Go's designers aren't idiots so I'm sure there are very good reasons they're championing this design, but C#/Rust/Java got it right with an Iterator interface that you pull values out of.