> let a = [| 'a'..'d' |];;
val a : char [] = [|'a'; 'b'; 'c'; 'd'|]
Do trivial slicing:
> a.[1..2], [1..2];;
val it : char [] * int list = ([|'b'; 'c'|], [1; 2])
Now try it with empty region:
> a.[1..0], [1..0];;
val it : char [] * int list = ([||], [])
Seems working and reasonable - we got two empty sequences.
But it fails here:
> a.[5..0];;
System.OverflowException: Arithmetic operation resulted in an overflow.
at <StartupCode$FSI_0018>.$FSI_0018.main@()
Stopped due to error
Of course, there is a workaround [| for i in [5..0] -> a.[i] |]
. But I miss the point why a.[5..0]
fails? Why not just return empty array? Any reasons for such behavior?
This is a bug.
Though array slicing and range expression are different concepts (you cannot use a.[1..2..5]
for example), they should behave consistently.
Notice that the exception happens with a.[start..finish]
when finish - start <= -2
(a.[3..1]
fails) and array slicing works fine if finish - start = -1
(a.[5..4] = [||]
).
Array slicing is done by using GetArraySlice function in prim-types.fs:
let inline GetArraySlice (arr: _[]) start finish =
let start = (match start with None -> 0 | Some n -> n)
let finish = (match finish with None -> arr.Length - 1 | Some n -> n)
GetArraySub arr start (finish - start + 1)
while GetArraySub
is implemented in the same module as follows:
let inline GetArraySub arr (start:int) (len:int) =
let dst = zeroCreate len
for i = 0 to len - 1 do
SetArray dst i (GetArray arr (start + i))
dst
If finish - start = -1
, we have len = 0
in GetArraySub
and zeroCreate 0
returns an empty array. It's no longer the case with finish - start <= -2
which leads to len < 0
and zeroCreate len
fails.
This could be fixed by always returning an empty array whenever finish - start <= -1
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With