apt1002 / multidimension

Pure Rust library providing high-level manipulation of multi-dimensional arrays
BSD 2-Clause "Simplified" License
1 stars 2 forks source link

Write `View::into_iter()` #15

Open Banyc opened 10 months ago

Banyc commented 10 months ago

Iterators are widely used in the Rust ecosystem. Iterators also enable inter-operations between crates with a simple interface. If View exposes an iterator, then the other crates can analyze a stream of numbers from the iterator without explicitly calling View::each().

apt1002 commented 10 months ago

Interesting idea, thank you.

I feel View is an alternative to Iterator. Many of the useful methods on Iterator also exist on View, where they are designed in a way which is more appropriate for data that is multi-dimensional, unordered and cloneable. It's not clear that an Iterator would ever be preferable for such data, just as it's not clear that a View would ever be preferable for representing a sequence. But let me suppose that you are right and it is desirable for some reason.

I've read your pull request, which I see implements Iterator in terms of from_usize(). I'm a bit conflicted about that idea, because from_usize() is quite embarrassingly bad. For example, it almost always does at least one division, and sometimes many. Of course this is not your fault in any way, but I generally try not to implement other things in terms of from_usize(). Its value is mostly as documentation.

Another way of turning a View into a sequence type is to collect it into an Array and extract the Vec from inside it. Though it involves allocating memory for the whole sequence, it benefits from each() which is likely to generate good code.

Another way might be for some types that implement Index to also implement IntoIterator. Of course this doesn't work, because a third-party crate (multidimension) cannot implement a standard library trait (IntoIterator) for a standard library type (e.g. tuples), and anyway you'd want a way to specify the Size. However, something similar could be made to work. Then View::iter() could easily be implemented in terms of that.

What do you think of these ideas?

Banyc commented 10 months ago

You are right that View is a n-dimensional data while an iterator is just a stream of data and they are different things. I think an iterator is the alternative to the API View::each() specifically, so the additional iterator API may still make sense since it adds a lot of functionalities what View::each() can't do currently, for instance, for item in v.iter().

I see you tried to avoid using the default implementation in View that involves using from_usize(). I thought for a while and came up with an idea, and not sure if it's ideal though. That is to implement an optimized iter() for each struct that implements View like the each() API, so that the iter() API can also avoid using from_usize().

apt1002 commented 10 months ago

Yes, or maybe better on the Index type? Then View can have a blanket implementation.

It needs a new trait, I think: a subtrait of Index. I've been mulling a redesign of Index anyway. I'll try to incorporate your idea.

Given that a good workaround exists (collecting into an Array, and then iterating through that) I don't feel this is urgent, so I'm going to take it slowly and get it right.