Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.Sign up
Add support for byref-like parameters for local functions #805
Add support for recursive loops / loop breaks for ref structs
One of the common scenarios in programming languages is situation when we want to iterate over the elements of the collection up to a given point, when our expectation has been satisfied and we don't need to iterate any longer. In many languages (like C#) this can be easily done with foreach loop combined with break/early return.
However in F# this is not the case. To achieve that the common patter is to use recursive loop, eg.:
let tryFind item array = let rec loop item array i = if i >= Array.length array then -1 elif array.[i] = item then i else loop item array (i+1) loop item array 0
Which will be unrolled by F# compiler into equivalent implementation with early return included. Problem is that this approach doesn't work when we want to pass ref struct (eg. ReadOnlySpan).
While I managed to work around this issue with variable flags, I don't thing it's expected way to work with things:
let tryFind item (span: ReadOnlySpan<_>) = let mutable i = 0 let mutable found = -1 while found = -1 && i < span.Length do if span.[i] = item then found <- i i <- i + 1 found
There are two possible ways to work with it:
Affidavit (please submit!)
Please tick this by placing a cross in the box:
Please tick all that apply:
You should probably change the title to:
The problem you are hitting is due to the lack of support for local functions having byref-like parameter types. You can do recursion just fine with byref-like types, you just need to make them top-level functions:
module Test let rec loop item (array: ReadOnlySpan<_>) i = if i >= array.Length then -1 elif array.[i] = item then i else loop item array (i+1)
This already works today.
But this example:
let topLevel () = let local (p: byref<int>) = p let mutable x = 1 local &x
Does not work and this is what is preventing from you from having this code:
let tryFind item array = let rec loop item (array: ReadOnlySpan<_>) i = if i >= array.Length then -1 elif array.[i] = item then i else loop item array (i+1) loop item array 0