Crystal: Assignment to unbounded (or empty) range of empty array should not fail

Created on 17 Oct 2019  路  5Comments  路  Source: crystal-lang/crystal

Consider the following examples

# This works
a = [1]
a[..] = [1,2,3]

# This fails with "Index out of bounds"
a = [] of Int32
a[..] = [1,2,3]

The latter seems to be a valid idiom for replacing the content of an array (in contrast a = [1,2,3] creates a new array). Also note that reading does work:

a = [] of Int32
puts a[..] # this is ok

One could argue whether replacement of empty ranges should work (i.e. it means "insertion") if the resulting array would not contain gaps. In other words, one could argue if the following examples should work or not:

#### The following examples should work
a = [1]
a[1..] = [2,3] # results in a = [1,2,3]

a = [1]
a[1...1] = [2,3] # as above because 1...1 is empty

# Note that insertion of empty ranges in the middle is does already work
a = [1,5]
a[1...1] = [2,3,4]  # results in a = [1,2,3,4,5]

#### The following examples should fail
a = [1]
a[2..] = [2, 3] # should fail because it would result in a = [1, XXX, 2, 3] where a[1] is undefined

a = [1]
a[1..1] = [2,3] # should fail because the non-empty range 1..1 is not valid for a.
bug topiccollection

All 5 comments

The way I see this is that if the initial index of the range is out of bounds, an index out-of-bounds error should be thrown. That would make this an error (which is the current behavior):

a = []
a[..] = [2,3]

Fair enough ... on the other hand a = [] of Int32; a[..] is valid.

Note that I totally agree that it could be interpreted your way. But at the same time I think that my interpretation is also a valid semantic model. Neither one is totally right or wrong.

But note that there are some inconsistencies (imho), e.g.

a = [] of Int32
a[..]  # -> []
a[0,0] # -> []
a[1..] # Index out of bounds
a[1,0] # Index out of bounds

Neither index 0 nor index 1 are valid for a in these examples. If you would assign then all four examples raise an Index out of bounds error.

My idea is basically that a[..] and something like a[...a.size] or a[..] = a[..] should always be valid (if the right-hand side is valid), no mather if a is empty or not. Of course, I'm not totally sure if this is a good idea ... ;)

btw, I think there's a bug in argument type restriction in Array(T)#[]?(range : Range(Int, Int)) - should be just Array(T)#[]?(range : Range).

I think array[...] = ... should never fail. [...] means replace whatever there is with the new content (so similar to replace).

@Sija Yes, it should definitely be equal to the other range type restrictions. Technically, they should probably all be Range(Int?, Int?).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jhass picture jhass  路  3Comments

costajob picture costajob  路  3Comments

RX14 picture RX14  路  3Comments

oprypin picture oprypin  路  3Comments

ArthurZ picture ArthurZ  路  3Comments