itertools icon indicating copy to clipboard operation
itertools copied to clipboard

What would be needed for an array-based version of Itertools::tuples(), etc?

Open HadrienG2 opened this issue 7 years ago • 9 comments

The use of tuples in Itertools::tuples() and friends is questionable:

  • It suggests that type heterogeneity in iterator output is possible, which isn't accurate
  • It requires underscore-heavy turbofishes in user code
  • It could never scale to large groups of outputs, since the tuple-based signature takes O(N) characters

I think it would often make more sense to group consecutive items in arrays, as opposed to tuples. Can we agree on this? And if so, what would be needed to make it happen? I'm ready to help code this.

HadrienG2 avatar Dec 07 '17 11:12 HadrienG2

Tuples support destructing in let, for and elsewhere and arrays do not and that's pretty much it. It is a practical decision. I'd require both array patterns and const generics to use arrays.

bluss avatar Dec 07 '17 19:12 bluss

Array patterns are already available in unstable form, but I can understand why you would want to wait for const generics as well. Otherwise, we would end up replacing one imperfect solution with another. Let's wait a bit, then...

HadrienG2 avatar Dec 07 '17 23:12 HadrienG2

unstable features doesn't matter to itertools, we'd need them to be stable of course. Having slice patterns would be exciting, and long overdue.

bluss avatar Dec 30 '17 12:12 bluss

As slice patterns are stable since 1.26, maybe we could revisit this at the next Rust version bump?

EDIT: Sorry, reading through the thread again, you wanted to await const generics too.

HadrienG2 avatar Oct 30 '18 21:10 HadrienG2

You have a point though, arrays are fine for pattern matching now. I'm mostly for practical arguments I think, but arrays can be practical.

bluss avatar Dec 09 '18 19:12 bluss

Const generics have been stabilized. So this is possible now:

fn get_ints<const N: usize>() -> [u32; N] {
    [(); N].map(|()| rand::random())
}

let [a, b, c] = get_ints();

I believe it’s time to add array versions of all tuple functions: tuples, tuple_windows, collect_tuple, etc. WDYT?

I would be happy to make a pull request.

amatveiakin avatar Oct 11 '23 11:10 amatveiakin

I agree it's time to do this, and we already have several PRs pending for it.

However, now the blocker isn't MSRV, but rather dependencies. At the time those PRs were filed, Rust was still missing key helpers for safely initializing arrays. The unsafe code needed for this is VERY subtle, and I do not want us to try to do it on our own. Those PRs worked around that by adding a dependency for array initialization, but itertools also takes a very conservative stance on dependencies.

The next step for this is to look at those PRs, see what routines can be replaced with standard library helpers, or else gate these array features (and the associated dependency) behind a cargo feature flag.

jswrenn avatar Oct 11 '23 11:10 jswrenn

Note that core::array::from_fn() can be used for many different array initialization scenarios, and generates pretty decent code on modern rustc versions.

HadrienG2 avatar Oct 11 '23 11:10 HadrienG2

With core::array::from_fn it's easy to write a function that returns an array or panics. In order to return an Option<[T; N]> we would need to first construct an [Option<T>; N], right? So if the goal is to avoid both unsafe code and performance overhead, then we need core::array::try_from_fn, which is not stable yet.

amatveiakin avatar Oct 11 '23 15:10 amatveiakin