5 ms·
That's nothing special though, `zip` just takes an item from each iterator, packs them into a tuple, and yields that. It has no weird bounds or requirements or
by masklinn 4y ago
That's nothing special though, `zip` just takes an item from each iterator, packs them into a tuple, and yields that. It has no weird bounds or requirements or anything: https://doc.rust-lang.org/std/iter/fn.zip.html https://doc.rust-lang.org/std/iter/fn.zip.html
The impl of the default `next` is:
fn next(&mut self) -> Option<(A::Item, B::Item)> {
let x = self.a.next()?;
let y = self.b.next()?;
Some((x, y))
}
So completely straightforward.
- brundolf 4y agoI was thinking about the fact that whatever you're iterating over has to be copied around throughout the process. Rust can guarantee that eg. deep-copies (clones) of allocated structs will never happen implicitly, if your iterator owns the values being iterated. But in languages where copying can trigger allocations, this could be a problem I don't actually know whether that applies to Zig though
- defen 4y agoCan that zip more than two iterators? And does it perform a bounds check on each call to `a.next()` and `b.next()`?
- brundolf 4y agoIt stops when one of the two iterators ends It can't zip more than two per se, but you could zip the result of the first zip into a third and get ((item1, item2), item3). You could then map these if you wanted, to flatten them into a single tuple .map(|((item1, item2), item3)| (item1, item2, item3)) Of course there's a trade-off here between ergonomics and generality
- masklinn 4y ago> It can't zip more than two per se, but you could zip the result of the first zip into a third and get ((item1, item2), item3). You could then map these if you wanted, to flatten them into a single tuple .map(|((item1, item2), item3)| (item1, item2, item3)) FWIW that's more or less what `itertools::izip!` does for you, it just chains `zip`s then "splats" them using a `map`.
- defen 4y ago> It stops when one of the two iterators ends Right; my question is, suppose you're iterating over two slice iterators - won't each call to `a.next()` and `b.next()` have to check whether that sub-iterator is done? One of the benefits of the Zig approach is that you can iterate over an arbitrary number of slices and do one check before entering the loop, followed by the compiler emitting unchecked index access in the loop. So it basically compiles down to the equivalent of a C `for` loop.
- masklinn 4y agoRust's zip has a specialisation for iterators with a trusted length. Such as slice iterators. `zip` yields exactly the same assembly as a loop over the index range with an unsafe item access: https://godbolt.org/z/7ebfxbhxc https://godbolt.org/z/7ebfxbhxc
- brundolf 4y agoInteresting, are "trusted-length" iterators something that might ever make it into userspace? Maybe as const generics?
- masklinn 4y agoIt’s already in userspace, though nightly (and unsafe, obviously), so whether it’ll be stabilised, and in what form, is an open question: https://doc.rust-lang.org/std/iter/trait.TrustedLen.html https://doc.rust-lang.org/std/iter/trait.TrustedLen.html
- kristoff_it 4y agoYou have to pass -O though, the point of Zig's for loop syntax is to get fast compile times and good performance also in debug mode :^)
- defen 4y agoThat's cool. At the same time though, it almost feels like a distinction without a difference in some ways - Zig has a special built-in syntax; Rust doesn't use special syntax, but it does use complex special-cased unsafe code in the stdlib in order to implement a safe + performant API.
- chlorion 4y agoYou can zip a zipper to combine them, but you end up with an item like (a, (b, (c, d))), not a huge deal since it gets destructured automatically. The itertools crate has a multizip function/macro that allows zipping as many iterators as you'd like without nesting zips inside of zips! I really recommend checking out itertools if you use rust and like iterators! It's a direct dependency of rustc itself too, which suggests its a trusted project (it may even be maintained by rust devs, not totally sure).
- laserbeam 4y agoYou're assuming that an iterator gets created and returned by zip. In zig the for loop syntax doesn't need the concept of an iterator. All you need is variables in a capture. That's what I mean by straightforward. You'd have to argue about the memory layout for an iterator, that you call functions on it etc. Lots of small decisions. In zig those things would usually be part of the standard library, not language features. If you want to call a next() function on a thing in zig, you want to be explicit. That's what the language means by "no hidden control flow". You'd use a while loop if you wanted to iterate on a hashmap for example. In some sense, this is less elegant, but it's usually more obvious what the compiler would end up doing in any bit of code.