I got this idea from reading the discussion in Make `<[T]>::array_*` methods fail to compile on 0 len arrays by AngelicosPhosphoros · Pull Request #99471 · rust-lang/rust · GitHub about how to forbid 0 as length for <[T]>::array_windows
. I don't have enough knowledge to comment on the original topic, but it got me thinking: why do we forbid 0 in the first place?
There is a mathematically consistent implementation for <[T]>::[array_]windows(0)
. Let's take a look at some other input:
[0, 1, 2].windows(3) -> [ [0, 1, 2] ]; iterator length = 1, window length = 3
[0, 1, 2].windows(2) -> [ [0, 1], [1, 2]]; iterator length = 2, window length = 2
[0, 1, 2].windows(1) -> [ [0], [1], [2] ]; iterator length = 3, window length = 1
(edit: fixed some off-by-1 error above) and if we extrapolate this, we get
[0, 1, 2].windows(0) -> [ [], [], [], [] ]; iterator length = 4, window length = 0
So a valid implementation of [_; N].windows(0)
is to return an iterator that yields N+1
items, and all items are empty slices. This might look silly, but it is consistent with all other input, and likely handles edge cases well for algorithm built on top of windows
. One can also argue this is the correct implementation with the intuition of a sliding window: windows(W)
iterator slides a window of length W
from the beginning to the end. The beginning is where the left side of the window is at the left side of the slice, while the end is where the right side of the window is at the right side of the slice. Applying this to W = 0
, we get the following sliding motion
[[ ]0, 1, 2, 3] => [0[,]1, 2, 3] => [0, 1[,]2, 3] => [0, 1, 2[,]3] => [0, 1, 2, 3 [ ]]
Changing the behavior for the stable function .windows
to this probably should be considered as a breaking change. However, we still have a chance to "correct" it for the unstable array_windows
function.
Some similars argument can be applied to the chunks
function family
[0, 1, 2].chunks(3) -> [ [0, 1, 2] ]; iterator length = 1 = 3 / 3, chunk length = 3
[0, 1, 2].chunks(2) -> [ [0, 1] ]; iterator length = 1 = 3 / 2, chunk length = 2
[0, 1, 2].chunks(1) -> [ [0], [1], [2] ]; iterator length = 3 = 3 / 1, chunk length = 1
So to extrapolate this, we should have
[0, 1, 2].chunks(0) -> [ [], [], [], .... ]; iterator length = inf = 3 / 0, chunk length = 0
This is even sillier because it produces an infinite iterator. It is still mathematically consistent, though. It can also be argued with a sliding window, with one modification: instead of moving one element forward at a time, the window moves forward by moving the new beginning to the old end. For 0-length chunk, the window can never move forward this way, hence it yields empty slices forever.