Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace IteratorExt::zip with tuple iteration #870

Closed
wants to merge 6 commits into from

Conversation

Projects
None yet
@oli-obk
Copy link
Contributor

oli-obk commented Feb 16, 2015

for (x, y, z) in (a, b, c) {
   // do something smart
}

Should iterate over a, b and c (if all of them implement IntoIterator) and return the current element of each of them in x, y, and z until any of a, b or c return None.

internals.rust-lang.org discussion

Rendered

@Gankro

This comment has been minimized.

Copy link
Contributor

Gankro commented Feb 16, 2015

Is this not a bit of a regression since you can theoretically indefinitely Zip, whereas with this you'll run into Tuple impl size limits quickly?

Otherwise my only objection to this is the vague "Rust is becoming more magic" problem (that I am incredibly guilty of exacerbating). But maybe this is more intuitive that there being a method called Zip?

@oli-obk

This comment has been minimized.

Copy link
Contributor Author

oli-obk commented Feb 16, 2015

If that would help my case for this RFC, I could collect a list of cries for help on stackoverflow of people trying to zip in several languages without knowing the keyword zip.

@shepmaster

This comment has been minimized.

Copy link
Member

shepmaster commented Feb 16, 2015

👎 I'll agree that I prefer to use a function named zip. Ruby and Clojure (two languages I am familiar with) have zip and I think it's reasonable to expect people to know the name.

Also your comment above:

I could collect a list of cries for help on stackoverflow of people trying to zip in several languages without knowing the keyword zip

Doesn't really jive with your statement in the forum:

true... although I'd assume stack-overflow solves [that it's hard to discover that tupling zips the iterators] after the question has been asked a few times

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Feb 16, 2015

@Gankro regarding the regression, I'm not sure I follow. Isn't todays zip just equivalent to a 2-tuple here? In particular, can't you nest tuples to achieve arbitrary iteration?

for (x, (y, z)) in (xs, (ys, zs)) { ... }

Or am I missing something?

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Feb 16, 2015

(I do think that as far as "guessability" goes, zip is probably more guessable than tuples, since it is used in so many languages.)

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Feb 16, 2015

I have mixed feelings. I feel like this approach is beautifully concise, but it may be a learning hazard. On the other hand, that's true for a lot of iterator magic (e.g., collecting into a Result<Vec<_>, _>), and once you know it, it's just so perty. Guess I'd just want to get a sense for what people at large feel.

(That said, for some reason now that for item in collection works, I keep sort of expecting for (a, b) in (as, bs) to work. Probably because I wind up typing the parallel structures of for item in collection, for &item in &collection, etc so often.)

@pczarn

This comment has been minimized.

Copy link

pczarn commented Feb 16, 2015

Perhaps I would like to have for (x, y, z) in (a, b, c).transpose() {} which is not as magical as IntoIterator, as I said once in the forum.

@Gankro

This comment has been minimized.

Copy link
Contributor

Gankro commented Feb 16, 2015

@nikomatsakis. Ah yes, you're right. Didn't occur to me that that would "just work".

@oli-obk

This comment has been minimized.

Copy link
Contributor Author

oli-obk commented Feb 17, 2015

i could live with .zip() on tuples, but I prefer to implement IntoIterator
@shepmaster of course it fits together. Many languages don't support such a feature (example: search for c++, iterate, multiple), and require third party libraries + some uncomfortable syntax. The first thing I tried when i needed zipping was to use tuples, which didn't work, but for me seemed like the thing that should work. Not sure if the general intuition comes to the same result.

@llogiq

This comment has been minimized.

Copy link
Contributor

llogiq commented Feb 17, 2015

What if someone implements IntoIter for arbitrary same-size tuples? I think it would not necessariily be ambiguous (because of the match on (x, y, z)), but it could throw off fellow developers who may be unsure what the code is doing.

@oli-obk

This comment has been minimized.

Copy link
Contributor Author

oli-obk commented Feb 17, 2015

@llogiq: i guess that's similar to someone implementing IntoIter for [T] or something. The compiler would tell you this exists already.

@petrochenkov

This comment has been minimized.

Copy link
Contributor

petrochenkov commented Feb 17, 2015

I think, bad searchability is a relatively weak argument against this proposal.
It usually works like: google "rust zip iterator" -> the first result is a stackoverflow answer with thousands of upvotes, describing the tuple notation in details. As an example, try to search "perl break", "python ternary operator" or "c string split".
(At least that is what I do when I have to use languages that I'm unfamiliar with, and it always works for basic things like zip even if the syntax is completely different.)

@Ericson2314

This comment has been minimized.

Copy link
Contributor

Ericson2314 commented Feb 17, 2015

Could this be done with polymorphic impls, or does it need to hefty syntactic support?

@oli-obk

This comment has been minimized.

Copy link
Contributor Author

oli-obk commented Feb 17, 2015

@Ericson2314 well we need some macro magic for tuples with 1 to n elements. n probably being something around 10

@Ericson2314

This comment has been minimized.

Copy link
Contributor

Ericson2314 commented Feb 17, 2015

I would have assumed this would work:

impl<I: IntoIter, J: IntoIter> impl IntoIter for (I, J) {
  type IntoIter= (<I as IntoIter>::IntoIter, <J as IntoIter>::IntoIter);
  ...
}

impl<I: Iter, J: Iter> impl Iter for (I, J) {
  type Item = (<I as IntoIter>::Item, <J as IntoIter>::Item);
  ...
}

and so on for larger tuples.

@oli-obk

This comment has been minimized.

Copy link
Contributor Author

oli-obk commented Feb 17, 2015

yes, that will be generated by macros, as to not repeat ourselves. I have a sample implementation in the rfc. it's rather blunt, but if the rfc is accepted i will actually put in an effort to make it nice

@Ericson2314

This comment has been minimized.

Copy link
Contributor

Ericson2314 commented Feb 17, 2015

Ok, just checking. I thought people were implying the feature itself would require compiler syntactic support, when really it's just that its implementation would benefit from it, but doesn't even need it.

I'm more for this then. Sure its a bit spooky but isn't proposing anything that couldn't be done already (baring coherence).

@Gankro

This comment has been minimized.

Copy link
Contributor

Gankro commented Feb 18, 2015

I've come around to this.

Let's lean into the magic together, everyone

@Gankro

This comment has been minimized.

Copy link
Contributor

Gankro commented Feb 18, 2015

Cool consequence when extend is upgraded to use IntoIterator:

some_map.extend((keys, vals))
@oli-obk

This comment has been minimized.

Copy link
Contributor Author

oli-obk commented Feb 23, 2015

I added another alternative: requiring .zip() which is discoverable and extendable to similar functions like .product() and .flatten(). Also, this rfc can be post-1.0 then.

@tikue

This comment has been minimized.

Copy link

tikue commented Feb 28, 2015

Ah...this is gorgeous! It's so obvious that I'm surprised it hasn't been brought up sooner.

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Feb 28, 2015

👍 This is amazing and I want it.
Those method chains can get rather tedious and I wish we'd use more operators for iterators, but without custom ones it would get confusing fast.

@cmr

This comment has been minimized.

Copy link
Member

cmr commented Feb 28, 2015

This is cute. I agree fully with @nikomatsakis though. I feel pretty hesitant about this.

@vwim

This comment has been minimized.

Copy link

vwim commented Feb 28, 2015

Looks nice but I think this should be solved in a more structural way instead of applying magic.

@petrochenkov

This comment has been minimized.

Copy link
Contributor

petrochenkov commented Feb 28, 2015

I like how intuitive this notation is.

How do you iterate through a list of elements?

for x in xs {}

How do you iterate through two lists simultaneously?
Well,

for x, y in xs, ys {}

, but with some parentheses required.
Simultaneous iteration is a very simple concept, much simpler than the underlying iterator machinery and zip itself. Someone should try it on children and report, I think the results will be positive :D

@brson brson referenced this pull request Mar 3, 2015

Open

Consider tuple iteration #930

@brson

This comment has been minimized.

Copy link
Contributor

brson commented Mar 3, 2015

While this is a clever idea with some promise, it is also very much a nice-to-have, and I'm strongly inclined to exercise discretion in adding new features to Rust at this time. I've opened #930 to let this idea continue to bake, but am closing this PR. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.