crystal-lang / crystal

The Crystal Programming Language
https://crystal-lang.org
Apache License 2.0
19.21k stars 1.61k forks source link

Discrepancy in `#[](start, count)` with negative start in array-like collections #14775

Open ysbaddaden opened 2 days ago

ysbaddaden commented 2 days ago

While trying get the last 3 bytes in a slice, I noticed that bytes[-3, 3] failed unexpectedly. Digging a bit, I noticed that there is a discrepancy in how [](start, count) with a negative start behaves in the different array-like collections:

Given that [](index) with a negative index is behaving the same in all these types (return item at index starting from the end), I'd expect [](count, start) to behave the same, too.

The method isn't implemented for StaticArray but it's likely deliberate (aka not possible). It may not make much sense for Deque either (though possible), but Slice was surprising.

HertzDevil commented 2 days ago

For Slice there is also #12617

straight-shoota commented 2 days ago

I suppose we should utilize Indexable.normalize_start_and_count in Slice#[]?. The purpose of this helper method is exactly to synchronize this behaviour across implementations.

We actually use it already in Slice#fill. However, there is also a comment mentioning the restricted behaviour of Slice#[] regarding count.

https://github.com/crystal-lang/crystal/blob/be46ba200c049772a625fb5c719ff7f9b198c0b1/src/slice.cr#L452-L456

And yeah, I find the implicit clamping of count can be a bit surprising. I would expect the result of slice[i, 8] to have 8 elements, not "up to 8" (Math.min(slice.size - i, 8)). I'd probably expect the same for Array as well. 🤷