Skip to content

Add while! (while-bang) keyword to computation expressions #1038

@mvkara

Description

@mvkara

Add while! (while-bang) keyword to computation expressions

I propose we extend the computation expression syntax with a new keyword, while!, that combines a let! and a typical while loop.

Using the current GRPC client as an example instead of writing something like...

task {
   let! firstRead = sender.ResponseStream.MoveNext(ct)
   let mutable read = firstRead
   while read do
     q.Push(sender.ResponseStream.Current)
     let! nextRead = sender.ResponseStream.MoveNext(ct)
     read <- nextRead
}

We should be able to do

task {
   while! sender.ResponseStream.MoveNext(ct) do
    q.Push(sender.ResponseStream.Current)
}

NOTE: That the typical approach for using recursion doesn't work for TaskBuilder's from my understanding since they aren't tail recursive in many libraries that provide them.

A similar problem exists when reading rows of an ADO.NET reader. If the while! syntax was allowed we would be able to do something like:

asyncSeq {
    // https://docs.microsoft.com/en-us/dotnet/api/system.data.common.dbdatareader.readasync?view=netcore-3.1
    while! reader.MoveNextAsync() do
        yield {| Column1 = reader.GetInt32(0); Column2 = reader.GetInt32(1) |}
}

Instead of:

asyncSeq {
   let rec yieldAsync() = asyncSeq {
      // https://docs.microsoft.com/en-us/dotnet/api/system.data.common.dbdatareader.readasync?view=netcore-3.1
      let! hasNext = reader.MoveNextAsync() |> Async.AwaitTask
      if hasNext
      then
          yield {| Column1 = reader.GetInt32(0); Column2 = reader.GetInt32(1) |}
          yield! yieldAsync()
   }
   yield! yieldAsync()
}

Pros and Cons

Pros: More concise code aiding readability, allows a more intuitive use of libraries exposing this pattern especially when given a Task API where using the recursive approach may not be supported, may offer a performance improvement for certain cases.

Cons: More work required to support this in the language and associated computational expressions (e.g. Task builders such as Ply).

Extra information

Estimated cost (XS, S, M, L, XL, XXL): S

Related suggestions:

#863

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

For Readers

If you would like to see this issue implemented, please click the 👍 emoji on this issue. These counts are used to generally order the suggestions by engagement.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions