Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistency with Array(T)#[]?(range : Range) when range is beginless or starts with 0. #13327

Open
stephannv opened this issue Apr 16, 2023 · 3 comments

Comments

@stephannv
Copy link

stephannv commented Apr 16, 2023

Bug Report

When using #[]? with a range, the behavior is different when using range.begin == 0 than when using range.begin != 0

Playground: link

array = [] of String

array[0..5]? # => []
array[..5]? # => []
array[1..5]? # => nil
array[-2..5]? # => nil
array[5..]? # => nil

The #[]?(range : Range) doc says:

Like #[](Range), but returns nil if range.begin is out of range.

But is 0 out of range? Yes.

array = [] of String
array[0] # => Unhandled exception: Index out of bounds (IndexError)

Maybe this is the cause: https://github.com/crystal-lang/crystal/blob/14bfa992e/src/array.cr#L661

System info:

Crystal 1.8.0 (2023-04-14)

LLVM: 15.0.7
Default target: aarch64-apple-darwin21.6.0
@stephannv
Copy link
Author

I think that the correct way following the documentation would be always returning nil in these cases.

But I think would be nice if []? returns [] in these cases. eg.: master...stephannv:crystal:patch-1 . But I'm not sure if this will break the Crystal philosophy.

Screen Shot 2023-04-16 at 20 40 48

@straight-shoota
Copy link
Member

straight-shoota commented Apr 17, 2023

This behaviour is not specific to the index 0. If you increase the size of the array as well as the accessor indices, you get the same result:

ary = [""]
ary[1..6]? # => [] of String
ary[2..6]? # => nil

If the start index is equivalent to the collection size, normalize_start_and_count accepts that and calculates the count of elements to be retrieved as 0.
I agree that this looks quite unexpected. I don't think think there's any reason for the first unset index to have a special meaning for this method.

@HertzDevil
Copy link
Contributor

I think the intent here is to allow one to refer to the empty subrange of elements at the end of an array:

arr = ["a", "b", "c"]
arr[3, 0] = "d"
arr # => ["a", "b", "c", "d"]

This is why the one-past-the-end start index is allowed for start + count overloads, even though it cannot be used to refer to a single element.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants