Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upTracking issue for Iterator::flatten #48213
Comments
Centril
added
T-libs
B-unstable
C-tracking-issue
labels
Feb 14, 2018
Centril
added a commit
to Centril/rust
that referenced
this issue
Feb 14, 2018
This comment has been minimized.
This comment has been minimized.
leonardo-m
commented
Feb 15, 2018
|
A flatten could be useful, but I think there are more important/useful functions/iterators to add before a flatten. |
This comment has been minimized.
This comment has been minimized.
|
@leonardo-m Clearly not important enough for someone to write a PR/RFC before this one, though. ;) |
This comment has been minimized.
This comment has been minimized.
|
Also I can't list the number of times I've done One thing that I think should be clarified is that this only flattens one level, i.e. it will not transform |
This comment has been minimized.
This comment has been minimized.
|
@leonardo-m I don't think it has to be an either-or proposition - if there are more useful additions, and there certainly are some from Itertools, they should be made irrespective of this one. Someone just has to write the PRs for those =) Regarding @clarcharr hmm, it does say in the docs that:
Perhaps that's not clear enough? Can we fix this during stabilization perhaps if it is not? |
This comment has been minimized.
This comment has been minimized.
|
@Centril I mentioned that having not actually read the docs yet. ;) I honestly think that including an example would be clearer; there are tools for languages such as JavaScript, for example, which will completely flatten an array regardless of how many levels it has. Although such a thing would be very difficult and/or impossible to do with Rust's type system, I think it'd be best for it to be clear that this is not a "deep" flatten, just a shallow one. |
This comment has been minimized.
This comment has been minimized.
|
@clarcharr Updated the docs with your example. |
Centril
added a commit
to Centril/rust
that referenced
this issue
Feb 16, 2018
This comment has been minimized.
This comment has been minimized.
|
Awesome! Thanks |
Centril
added a commit
to Centril/rust
that referenced
this issue
Feb 20, 2018
Centril
added a commit
to Centril/rust
that referenced
this issue
Feb 20, 2018
Centril
referenced this issue
Feb 25, 2018
Merged
RFC: Add `pub fn identity<T>(x: T) -> T { x }` to core::convert #2306
This comment has been minimized.
This comment has been minimized.
yrashk
commented
Feb 26, 2018
|
Not sure, how important this angle is, but just in case -- it looks like this introduces a failure for nightly builds on code that relies on itertools' version of flatten: https://it.sit-it.org/issue/fe5e68e5-22a1-4bc3-8ebf-36586460ba27 It's a trivial fix for the code that uses it (the patch is in the first link) but I thought it is worth mentioning this aspect. |
yrashk
added a commit
to sit-fyi/sit
that referenced
this issue
Feb 26, 2018
This comment has been minimized.
This comment has been minimized.
Vurich
commented
Feb 26, 2018
|
I don't think arbitrary-level flattening is impossible with Rust's type system, it's just that it would rely on specialisation and could produce confusing results. For example, Also, this would cause an infinite loop in the compiler when resolving the output type of struct Foo;
impl Iterator for Foo {
type Item = Foo;
fn next(&mut self) -> Foo {
unimplemented!()
}
}JS is dynamically typed and so deep flattening is useful since you don't know the nesting level until runtime. With Rust you know ahead of time precisely how many levels deep an iterator will be nested. |
This comment has been minimized.
This comment has been minimized.
SoniEx2
commented
Feb 28, 2018
|
Perhaps mention that this is more useful with scan instead of map? https://bitbucket.org/SoniEx2/wcc-rs/src/e07c866224a84accda05fa7fd4d956a185daabf7/src/lib.rs?at=master&fileviewer=file-view-default#lib.rs-147:157 |
This comment has been minimized.
This comment has been minimized.
|
@SoniEx2 I think the documentation has a sufficient number of examples, more would be too many. |
This comment has been minimized.
This comment has been minimized.
leonardo-m
commented
Feb 28, 2018
I don't agree. So far in my whole codebase I have seen zero places where to use a flatten(), on the other hand from the standard library I miss several iterable things already present in itertools. The API of the std library should be kept small. Adding functions is not free, the more things you add, the more time you need to use the API and find the right function. In my opinion the whole business of adding iterators to the Rust std library is currently broken. It should be based on real data. What are the most used iterators of the itertools crate? Add those to the std library. |
This comment has been minimized.
This comment has been minimized.
SoniEx2
commented
Feb 28, 2018
|
I have written scan+flat_map(|x|x) at least 3 times so far. And I don't even use Rust that often yet! The more I use rust, the more I run into scan+flatten. See also: rust-lang/rfcs#1978 It's most useful for string parsing, and partial collects. |
kennytm
referenced this issue
Mar 10, 2018
Open
Tracking issue for `unstable_name_collision` compatibility lint #48919
kirushik
referenced this issue
Mar 26, 2018
Closed
"multiple applicable items in scope" & "multiple `flatten` found" (while compiling from source) #8211
matthiasbeyer
referenced this issue
May 11, 2018
Merged
Fix: Explicitely use Itertools::flatten() #1491
This comment has been minimized.
This comment has been minimized.
|
@SimonSapin This has been in nightly for a few months now; could we stabilize? |
This comment has been minimized.
This comment has been minimized.
|
We may want another (check-only) crater run before stabilizing due to conflict with |
This comment has been minimized.
This comment has been minimized.
|
@reuvenpo How would that work exactly? As far as I know the type system cannot express this sort of type-level recursion (and boundary condition). |
This comment has been minimized.
This comment has been minimized.
reuvenpo
commented
Jun 11, 2018
•
|
To be honest, I'm still fairly new to rust and found my way here looking for this sort of feature, so I don't know for certain whether this sort of thing is possible. But at least theoretically, there exists a type system not much different from the subset of the rust type system that I'm familiar with, which would be able to statically generate concrete functions that flatten a nested structure, based on its type. As you said, that would require type-level recursion with a stop condition. I was hoping that someone with more in-depth knowledge of the current type system than myself would come across this thread and determine if it's possible or not. |
This comment has been minimized.
This comment has been minimized.
|
In either case, whether it is possible or not, I don't think a nested flatten operation should be called |
This comment has been minimized.
This comment has been minimized.
reuvenpo
commented
Jun 11, 2018
|
I've been thinking about this issue for a while, and i came up with something, but sadly i don't currently have the time to try a full implementation, so I'll write down a sketch of it, maybe it makes some sense (If it does I'll invest a few hours into learning how to properly contribute over the weekend). Basically, have a trait |
This comment has been minimized.
This comment has been minimized.
|
I did some experimentation: https://play.rust-lang.org/?gist=1bbdca273415c488e2f058d39fe995b2&version=nightly&mode=debug |
This comment has been minimized.
This comment has been minimized.
|
@reuvenpo That sounds maybe plausible with specialization of a trait that has an associated type (for the returned iterator). But the design of the trait specialization feature itself in the language is still evolving, so it might be a long time before "deep flatten" is possible at all. In the mean time, the existing |
Centril
referenced this issue
Jun 11, 2018
Merged
Stabilize Iterator::flatten in 1.29, fixes #48213. #51511
bors
added a commit
that referenced
this issue
Jun 11, 2018
This comment has been minimized.
This comment has been minimized.
reuvenpo
commented
Jun 12, 2018
•
|
Would it be appropriate to open a tracking issue for Or should an RFC be made first? |
This comment has been minimized.
This comment has been minimized.
Vurich
commented
Jun 13, 2018
•
|
Generally it's considered bad practice to have the behaviour rely on specialisation (rather than specialisation being an optimisation) because it means that In JavaScript the |
This comment has been minimized.
This comment has been minimized.
reuvenpo
commented
Jun 16, 2018
•
|
@Vurich, i'll start by addressing the second part of your message, and then elaborate on it, hopefully answering the first part too. It's true that in dynamically typed languages this is useful because both the author and the language may not know the depth of nesting for a given object, but it doesn't necessarily mean that in a statically typed language the author would like to care about the level of nesting of a given object, in some contexts. My example would be anything resembling a tree structure with unbounded depth (For example a directory structure). It may be desirable to have a function generalizes over In this context, say you had a function that received a structure whose concrete type was something like The type information is all there, it's just impossible to use currently, for these purposes. It would be best if you couldn't call Under this system, Of course, this is all pretty difficult, if at all possible, to implement today. I certainly don't know the "right" way to do this, if it was possible, I just think this interface makes sense and is doable, even if it still requires some features that aren't yet stabilized, or available at all. P.S. Obviously for cases where the concrete type is known, one can just call EDIT 1: changed |
This comment has been minimized.
This comment has been minimized.
SoniEx2
commented
Jun 16, 2018
|
"unnestable" is weird for a trait name. it sounds like you can't put it inside stuff. |
This comment has been minimized.
This comment has been minimized.
reuvenpo
commented
Jun 16, 2018
•
|
The name is just a proposal too. It can be called anything else that makes sense. ( |
This comment has been minimized.
This comment has been minimized.
Vurich
commented
Jun 18, 2018
|
The design where you specify the iterator type still fails for this: struct Foo;
impl Iterator for Foo {
type Item = Foo;
fn next(&mut self) -> Foo {
Foo
}
} |
This comment has been minimized.
This comment has been minimized.
reuvenpo
commented
Jun 18, 2018
|
I'm not sure i understand. (Is that even a useful pattern?) |
This comment has been minimized.
This comment has been minimized.
SoniEx2
commented
Jun 18, 2018
|
It would (should) do the least amount of work to return the desired result. You want an Iterator<Item=Foo>? Easy, one operation. You want an Foo? Zero operations. You want Iterator<Item=Iterator<Item=Foo>>? Also mostly easy. Etc. |
This comment has been minimized.
This comment has been minimized.
reuvenpo
commented
Jun 18, 2018
|
I don't see where i would use this pattern (since it prevents Foo from being an iterator over anything else, and this is a weird recursive way of doing what But again... What is the use case? Would in that use case it be useful to treat a |
This comment has been minimized.
This comment has been minimized.
|
Can we move discussion on flattening nested stuff to internals.rust-lang.org? |
This comment has been minimized.
This comment has been minimized.
reuvenpo
commented
Jun 18, 2018
|
(I'll have to open an account, but) |
Centril commentedFeb 14, 2018
Tracking issue for #48115,
Iterator::flattenandFlatMap.