# OK:
"abcd"[3,1] # "d" : String
"abcd"[5,1] # Index out of bounds
# FAIL (should be "Index out of bounds")
"abcd"[4,1] # "" : String
This is expected behaviour. The docs say:
Raises IndexError if start isn't in range.
Raises ArgumentError if #count is negative.
In the last case start is in range and count isn't negative, so it works. And I don't think it should raise, it's useful to get a substring from a starting position with at most count chars.
@asterite the range is zero-based, so it should be in 0..length-1
"ab"[0,1] # "a" : String
"ab"[1,1] # "b" : String
"ab"[2,1] # "" : String ?? ERROR
@asterite the differences below don't look right :
"ab"[0] # "a" : String
"ab"[1] # "b" : String
"ab"[2] # Index out of bound # OK
"ab"[3] # Index out of bound # OK
"ab"[0,1] # "a" : String
"ab"[1,1] # "b" : String
"ab"[2,1] # "" : String <<<<< ?!
"ab"[3,1] # Index out of bound # OK
Question: why do you want it to raise in those cases?
What about this:
"hello"[0..10] # should raise or not?
The meaning of [] with start, count or range is to get at most count chars from the range, less could be returned (probably not well explained in the docs). I didn't have a problem with this behavior in Ruby nor in Crystal. We will need good reasons to change this.
@asterite
1/
start > length-1. #[start, count] ( not for #[index] 2/
Question: why do you want it to raise in those cases?
Crystal already raises an error when start is too big:
"ab"[3,1] # Index out of bound # OK
My point is that Crystal is off-by-1 wrong (see b3 below; should behave like b4, as we start past the string's end) :
a1 : "ab"[0] # "a" : String
a2 : "ab"[1] # "b" : String
a3 : "ab"[2] # raises Index out of bound
a4 : "ab"[3] # raises Index out of bound
b1 : "ab"[0,1] # "a" : String
b2 : "ab"[1,1] # "b" : String
b3 : "ab"[2,1] # "" : String <<<<< WRONG
b4 : "ab"[3,1] # raises Index out of bound
Crystal is consistent with Ruby here: where Ruby returns nil, Crystal raises an exception. And where you say "WRONG", Ruby also returns an empty String. I did it this way because I think Ruby's behaviour is correct, but of course we can discuss if Ruby's semantics are correct here.
@asterite you're right about b3 (Ruby returns ""), but it's very odd.
It's very confusing that those 3 raise an error
a = ["a", "b", "c"]
a[3] # raises an Index out of bounds
a[4] # raises an Index out of bounds
a[5] # raises an Index out of bounds
but only the last two do
a[3,1] # []
a[4,1] # raises an Index out of bounds
a[5,1] # raises an Index out of bounds
If start is another name for the zero-based index - and I think it is; see a3 - then it should raise an Index error (as it is an invalid - too big by 1 ) index).
but of course we can discuss if Ruby's semantics are correct here.
I think we should indeed.
I want to highlight/clear up an important detail that wasn't really mentioned in this discussion yet: String#[](range : Range)/Array#[](Range) and String#[](start : Int32, count : Int32)/`Array#[](start : Int32, count : Int32) have a vastly different semantic. The former is "give me all elements between index a (range.begin) and index b (range.end)", the latter is "give me count elements starting from index start".
I can see how specifying an out of bounds index should raise, so I can see why the former variant should raise if the end index is out of bounds. However in the latter variant interpreting count as "up to count" makes total sense (IMO more than not) and should not be subject to raising bounds checks.
@jhass my question is : why raise an error if the index is past by 2 or more (current behaviour), but not if just past by 1? It's too big/out of bound in both cases.
@alainravet
my question is : why raise an error if the index is past by 2 or more (current behaviour), but not if just past by 1? It's too big/out of bound in both cases.
With a = ["a", "b", "c"] you have:
When you do a[3], you are asking for exactly one _value_ and it is not available there. When you do a[3,N], you are asking for an _array_ of up to N elements and 0 is a valid size for an array too.
Either way, I definitely would not want to see any unnecessary and non-obvious differences between Ruby and Crystal.
I'm closing this. The semantic of [] is "up to count elements", and the current implementation does that.
Most helpful comment
@alainravet
With
a = ["a", "b", "c"]you have:When you do
a[3], you are asking for exactly one _value_ and it is not available there. When you doa[3,N], you are asking for an _array_ of up to N elements and 0 is a valid size for an array too.Either way, I definitely would not want to see any unnecessary and non-obvious differences between Ruby and Crystal.