Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

weird behaviour of array slicing

Tags:

arrays

slice

f#

> 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?

like image 250
qehgt Avatar asked Apr 22 '12 15:04

qehgt


1 Answers

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.

like image 165
pad Avatar answered Oct 17 '22 05:10

pad