Search code examples
f#byref

Why is this not a valid usage of byref?


let iter2D (map: 'T byref -> unit) (arr: 'T[][]) =
    for y = 0 to arr.Length - 1 do
        let row = arr.[y]
        for x = 0 to row.Length - 1 do
            let mutable elem = arr.[y].[x]
            map &elem

The last line has: "The address of the variable 'elem' cannot be used at this point." What's wrong?


Solution

  • In F# 'T byref appears as a regular type, but under the cover, it is not - it corresponds to ref and out parameters in C# and those are special annotations on method arguments. This is why 'T byref is a bit odd in F#.

    I think you won't be able to use it through ordinary F# functions, because a function T1 -> T2 is compiled as FSharpFunc<T1, T2> with a method T2 Invoke(T1 arg) - and you cannot pass the byref type to generics (as it is not a real type).

    A workaround is to define your own delegate that has byref type:

    type FastAction<'T> = delegate of 'T byref -> unit
    

    With this, you can write iter2D that iterates directly over the array:

    let iter2D (map:FastAction<'T>) (arr: 'T[][]) =
        for y = 0 to arr.Length - 1 do
            let row = arr.[y]
            for x = 0 to row.Length - 1 do
                map.Invoke(&arr.[y].[x])
    

    The following will then mutate the value inside the array:

    let arr = [| [| 0 |] |]
    iter2D (FastAction(fun a -> a <- 10)) arr