Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for byref-like parameters for local functions #805

Closed
5 of 6 tasks
Horusiath opened this issue Nov 8, 2019 · 5 comments
Closed
5 of 6 tasks

Add support for byref-like parameters for local functions #805

Horusiath opened this issue Nov 8, 2019 · 5 comments

Comments

@Horusiath
Copy link

Horusiath commented Nov 8, 2019

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:

  1. Enable recursive loops to work with ref structs as an input (which I admit is preferred one, as it keeps a language feature set consistent over supported types and has broader applicability).
  2. Introduce early returns (like break and return statements) to the language.

Extra information

Related issues:

Affidavit (please submit!)

Please tick this by placing a cross in the box:

  • This is not a question (e.g. like one you might ask on stackoverflow) and I have searched stackoverflow for discussions of this issue
  • I have searched both open and closed suggestions on this site and believe this is not a duplicate
  • This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it.

Please tick all that apply:

  • This is not a breaking change to the F# language design
  • I or my company would be willing to help implement...
  • ... and/or test this
@TIHan
Copy link

TIHan commented Nov 8, 2019

You should probably change the title to:
Add support for byref-like parameters for local functions

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

@Horusiath Horusiath changed the title Add support for recursive loops / loop breaks for ref structs Add support for byref-like parameters for local functions Nov 8, 2019
@cartermp
Copy link
Member

cartermp commented Nov 8, 2019

@TIHan what are your thoughts on enabling this kind of pattern?

@cartermp
Copy link
Member

Will close this in favor of #805 which is the more general issue

@abelbraaksma
Copy link
Member

Ehhh, you linked this to itself, what issue did you mean is the more general one @cartermp? (I don't think it's #688, er that's about inlining and byref).

@cartermp
Copy link
Member

Yep, thanks for the catch. this is the one #887

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants