Asik
Asik

Reputation: 22133

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?

Upvotes: 4

Views: 388

Answers (1)

Tomas Petricek
Tomas Petricek

Reputation: 243051

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

Upvotes: 8

Related Questions