From ec5d9c2552e12f4e85949787a2c3645549783285 Mon Sep 17 00:00:00 2001 From: Ruben Bartelink Date: Sun, 31 Mar 2024 10:59:30 +0100 Subject: [PATCH 1/7] Utils naming/xmldoc polish --- src/FSharp.Control.TaskSeq/Utils.fs | 18 +++++++----------- src/FSharp.Control.TaskSeq/Utils.fsi | 24 ++++++++++++------------ 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/src/FSharp.Control.TaskSeq/Utils.fs b/src/FSharp.Control.TaskSeq/Utils.fs index c02bab35..63e0798f 100644 --- a/src/FSharp.Control.TaskSeq/Utils.fs +++ b/src/FSharp.Control.TaskSeq/Utils.fs @@ -2,8 +2,6 @@ namespace FSharp.Control open System.Threading.Tasks open System -open System.Diagnostics -open System.Threading [] module ValueTaskExtensions = @@ -24,15 +22,15 @@ module ValueTask = let inline ofSource taskSource version = ValueTask(taskSource, version) let inline ofTask (task: Task<'T>) = ValueTask<'T> task - let inline ignore (vtask: ValueTask<'T>) = + let inline ignore (valueTask: ValueTask<'T>) = // this implementation follows Stephen Toub's advice, see: // https://github.com/dotnet/runtime/issues/31503#issuecomment-554415966 - if vtask.IsCompletedSuccessfully then + if valueTask.IsCompletedSuccessfully then // ensure any side effect executes - vtask.Result |> ignore + valueTask.Result |> ignore ValueTask() else - ValueTask(vtask.AsTask()) + ValueTask(valueTask.AsTask()) [] let inline FromResult (value: 'T) = ValueTask<'T> value @@ -72,14 +70,12 @@ module Async = let inline ofTask (task: Task<'T>) = Async.AwaitTask task let inline ofUnitTask (task: Task) = Async.AwaitTask task let inline toTask (async: Async<'T>) = task { return! async } - let inline bind binder (task: Async<'T>) : Async<'U> = ExtraTopLevelOperators.async { return! binder task } - let inline ignore (async': Async<'T>) = async { - let! _ = async' - return () - } + let inline ignore (async: Async<'T>) = Async.Ignore async let inline map mapper (async: Async<'T>) : Async<'U> = ExtraTopLevelOperators.async { let! result = async return mapper result } + + let inline bind binder (async: Async<'T>) : Async<'U> = ExtraTopLevelOperators.async { return! binder async } diff --git a/src/FSharp.Control.TaskSeq/Utils.fsi b/src/FSharp.Control.TaskSeq/Utils.fsi index d34a1e57..13b7e205 100644 --- a/src/FSharp.Control.TaskSeq/Utils.fsi +++ b/src/FSharp.Control.TaskSeq/Utils.fsi @@ -24,13 +24,13 @@ module ValueTask = /// /// The function is deprecated since version 0.4.0, - /// please use in its stead. See . + /// please use in its stead. See . /// [] val inline FromResult: value: 'T -> ValueTask<'T> /// - /// Initialized a new instance of with an representing + /// Initializes a new instance of with an /// representing its operation. /// val inline ofSource: taskSource: IValueTaskSource -> version: int16 -> ValueTask @@ -42,15 +42,18 @@ module ValueTask = [] val inline ofIValueTaskSource: taskSource: IValueTaskSource -> version: int16 -> ValueTask - /// Creates a ValueTask form a Task<'T> + /// Creates a ValueTask from a Task<'T> val inline ofTask: task: Task<'T> -> ValueTask<'T> - /// Ignore a ValueTask<'T>, returns a non-generic ValueTask. - val inline ignore: vtask: ValueTask<'T> -> ValueTask + /// Convert a ValueTask<'T> into a non-generic ValueTask, ignoring the result + val inline ignore: valueTask: ValueTask<'T> -> ValueTask module Task = - /// Convert an Async<'T> into a Task<'T> + /// Create a task from a value + val inline fromResult: value: 'U -> Task<'U> + + /// Starts a running instance of an Async<'T>, represented as a Task<'T> val inline ofAsync: async: Async<'T> -> Task<'T> /// Convert a unit-task into a Task @@ -80,9 +83,6 @@ module Task = /// Bind a Task<'T> val inline bind: binder: ('T -> #Task<'U>) -> task: Task<'T> -> Task<'U> - /// Create a task from a value - val inline fromResult: value: 'U -> Task<'U> - module Async = /// Convert an Task<'T> into an Async<'T> @@ -91,14 +91,14 @@ module Async = /// Convert a unit-task into an Async val inline ofUnitTask: task: Task -> Async - /// Convert a Task<'T> into an Async<'T> + /// Starts a running instance of an Async<'T>, represented as a Task<'T> val inline toTask: async: Async<'T> -> Task<'T> /// Convert an Async<'T> into an Async, ignoring the result - val inline ignore: async': Async<'T> -> Async + val inline ignore: async: Async<'T> -> Async /// Map an Async<'T> val inline map: mapper: ('T -> 'U) -> async: Async<'T> -> Async<'U> /// Bind an Async<'T> - val inline bind: binder: (Async<'T> -> Async<'U>) -> task: Async<'T> -> Async<'U> + val inline bind: binder: (Async<'T> -> Async<'U>) -> async: Async<'T> -> Async<'U> From e5a128ca6b046e8c821978a61093646e7f278dfc Mon Sep 17 00:00:00 2001 From: Ruben Bartelink Date: Sun, 31 Mar 2024 11:06:17 +0100 Subject: [PATCH 2/7] Lint --- src/FSharp.Control.TaskSeq/Utils.fsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FSharp.Control.TaskSeq/Utils.fsi b/src/FSharp.Control.TaskSeq/Utils.fsi index 13b7e205..dacc1689 100644 --- a/src/FSharp.Control.TaskSeq/Utils.fsi +++ b/src/FSharp.Control.TaskSeq/Utils.fsi @@ -6,10 +6,10 @@ open System.Threading.Tasks.Sources [] module ValueTaskExtensions = - type System.Threading.Tasks.ValueTask with + type ValueTask with /// (Extension member) Gets a task that has already completed successfully. - static member inline CompletedTask: System.Threading.Tasks.ValueTask + static member inline CompletedTask: ValueTask module ValueTask = From 72224295fa87088890acb3cc8d1fc3e1cfebbd8f Mon Sep 17 00:00:00 2001 From: Ruben Bartelink Date: Sun, 31 Mar 2024 11:21:13 +0100 Subject: [PATCH 3/7] non- consistency --- src/FSharp.Control.TaskSeq/TaskSeq.fsi | 4 ++-- src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs | 4 ++-- src/FSharp.Control.TaskSeq/Utils.fsi | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/FSharp.Control.TaskSeq/TaskSeq.fsi b/src/FSharp.Control.TaskSeq/TaskSeq.fsi index cb5eefe5..ff98586c 100644 --- a/src/FSharp.Control.TaskSeq/TaskSeq.fsi +++ b/src/FSharp.Control.TaskSeq/TaskSeq.fsi @@ -274,7 +274,7 @@ type TaskSeq = static member append: source1: TaskSeq<'T> -> source2: TaskSeq<'T> -> TaskSeq<'T> /// - /// Concatenates a task sequence with a non-async F# in + /// Concatenates a task sequence with a (non-async) F# in /// and returns a single task sequence. /// /// @@ -285,7 +285,7 @@ type TaskSeq = static member appendSeq: source1: TaskSeq<'T> -> source2: seq<'T> -> TaskSeq<'T> /// - /// Concatenates a non-async F# in with a task sequence in + /// Concatenates a (non-async) F# in with a task sequence in /// and returns a single task sequence. /// /// diff --git a/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs b/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs index 958678ab..0b2e370e 100644 --- a/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs +++ b/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs @@ -525,9 +525,9 @@ module LowPriority = // and we need a way to distinguish these two methods. // // Types handled: - // - ValueTask (non-generic, because it implements GetResult() -> unit) + // - (non-generic) ValueTask (because it implements GetResult() -> unit) // - ValueTask<'T> (because it implements GetResult() -> 'TResult) - // - Task (non-generic, because it implements GetResult() -> unit) + // - (non-generic) Task (because it implements GetResult() -> unit) // - any other type that implements GetAwaiter() // // Not handled: diff --git a/src/FSharp.Control.TaskSeq/Utils.fsi b/src/FSharp.Control.TaskSeq/Utils.fsi index dacc1689..aecada8d 100644 --- a/src/FSharp.Control.TaskSeq/Utils.fsi +++ b/src/FSharp.Control.TaskSeq/Utils.fsi @@ -56,10 +56,10 @@ module Task = /// Starts a running instance of an Async<'T>, represented as a Task<'T> val inline ofAsync: async: Async<'T> -> Task<'T> - /// Convert a unit-task into a Task + /// Convert a non-generic Task into a Task val inline ofTask: task': Task -> Task - /// Convert a non-task function into a task-returning function + /// Convert a plain function into a task-returning function val inline apply: func: ('a -> 'b) -> ('a -> Task<'b>) /// Convert a Task<'T> into an Async<'T> @@ -69,8 +69,8 @@ module Task = val inline toValueTask: task: Task<'T> -> ValueTask<'T> /// - /// Convert a ValueTask<'T> to a Task<'T>. To use a non-generic ValueTask, - /// consider using: . + /// Convert a ValueTask<'T> to a Task<'T>. For a non-generic ValueTask, + /// consider: . /// val inline ofValueTask: valueTask: ValueTask<'T> -> Task<'T> @@ -88,7 +88,7 @@ module Async = /// Convert an Task<'T> into an Async<'T> val inline ofTask: task: Task<'T> -> Async<'T> - /// Convert a unit-task into an Async + /// Convert a non-generic Task into an Async val inline ofUnitTask: task: Task -> Async /// Starts a running instance of an Async<'T>, represented as a Task<'T> From c1ac47170f76835cfcfc796dd2429d4e82c0b98d Mon Sep 17 00:00:00 2001 From: Ruben Bartelink Date: Sat, 6 Apr 2024 20:53:50 +0100 Subject: [PATCH 4/7] Cleanup CompletedTask --- src/FSharp.Control.TaskSeq/Utils.fs | 10 ++-------- src/FSharp.Control.TaskSeq/Utils.fsi | 4 +++- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/FSharp.Control.TaskSeq/Utils.fs b/src/FSharp.Control.TaskSeq/Utils.fs index 63e0798f..ec076f20 100644 --- a/src/FSharp.Control.TaskSeq/Utils.fs +++ b/src/FSharp.Control.TaskSeq/Utils.fs @@ -1,20 +1,15 @@ namespace FSharp.Control -open System.Threading.Tasks open System +open System.Threading.Tasks [] module ValueTaskExtensions = - /// Extensions for ValueTask that are not available in NetStandard 2.1, but are - /// available in .NET 5+. We put them in Extension space to mimic the behavior of NetStandard 2.1 type ValueTask with - - /// (Extension member) Gets a task that has already completed successfully. static member inline CompletedTask = - // This mimics how it is done in .NET itself + // This mimics how it is done in net5.0 and later internally Unchecked.defaultof - module ValueTask = let False = ValueTask() let True = ValueTask true @@ -38,7 +33,6 @@ module ValueTask = [] let inline ofIValueTaskSource taskSource version = ofSource taskSource version - module Task = let inline fromResult (value: 'U) : Task<'U> = Task.FromResult value let inline ofAsync (async: Async<'T>) = task { return! async } diff --git a/src/FSharp.Control.TaskSeq/Utils.fsi b/src/FSharp.Control.TaskSeq/Utils.fsi index aecada8d..86d9dd44 100644 --- a/src/FSharp.Control.TaskSeq/Utils.fsi +++ b/src/FSharp.Control.TaskSeq/Utils.fsi @@ -6,9 +6,11 @@ open System.Threading.Tasks.Sources [] module ValueTaskExtensions = + + /// Shims back-filling .NET 5+ functionality for use on netstandard2.1 type ValueTask with - /// (Extension member) Gets a task that has already completed successfully. + /// (Extension member) Gets a ValueTask that has already completed successfully. static member inline CompletedTask: ValueTask module ValueTask = From 377025a3dd96be5daf71da1e9262e6f9118c3eeb Mon Sep 17 00:00:00 2001 From: Ruben Bartelink Date: Sat, 6 Apr 2024 21:16:32 +0100 Subject: [PATCH 5/7] Reword Async.toTask/Task.ofAsync summary --- src/FSharp.Control.TaskSeq/Utils.fsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FSharp.Control.TaskSeq/Utils.fsi b/src/FSharp.Control.TaskSeq/Utils.fsi index 86d9dd44..ec7badd6 100644 --- a/src/FSharp.Control.TaskSeq/Utils.fsi +++ b/src/FSharp.Control.TaskSeq/Utils.fsi @@ -55,7 +55,7 @@ module Task = /// Create a task from a value val inline fromResult: value: 'U -> Task<'U> - /// Starts a running instance of an Async<'T>, represented as a Task<'T> + /// Starts the `Async<'T>` computation, returning the associated `Task<'T>` val inline ofAsync: async: Async<'T> -> Task<'T> /// Convert a non-generic Task into a Task From 593db0d15cf7871de08e4015173f7dbffad37513 Mon Sep 17 00:00:00 2001 From: Ruben Bartelink Date: Sat, 6 Apr 2024 21:24:30 +0100 Subject: [PATCH 6/7] Align fromResult summary with .NET FW --- src/FSharp.Control.TaskSeq/Utils.fsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FSharp.Control.TaskSeq/Utils.fsi b/src/FSharp.Control.TaskSeq/Utils.fsi index ec7badd6..fab0cb2a 100644 --- a/src/FSharp.Control.TaskSeq/Utils.fsi +++ b/src/FSharp.Control.TaskSeq/Utils.fsi @@ -52,7 +52,7 @@ module ValueTask = module Task = - /// Create a task from a value + /// Creates a Task<'U> that's completed successfully with the specified result. val inline fromResult: value: 'U -> Task<'U> /// Starts the `Async<'T>` computation, returning the associated `Task<'T>` From b4ce4ee4690cbcc6545445a75d44ba656718e93b Mon Sep 17 00:00:00 2001 From: Ruben Bartelink Date: Sat, 13 Apr 2024 14:16:59 +0100 Subject: [PATCH 7/7] Straggler, align Async.toTask with Task.toAsync --- src/FSharp.Control.TaskSeq/Utils.fsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FSharp.Control.TaskSeq/Utils.fsi b/src/FSharp.Control.TaskSeq/Utils.fsi index fab0cb2a..b1717204 100644 --- a/src/FSharp.Control.TaskSeq/Utils.fsi +++ b/src/FSharp.Control.TaskSeq/Utils.fsi @@ -93,7 +93,7 @@ module Async = /// Convert a non-generic Task into an Async val inline ofUnitTask: task: Task -> Async - /// Starts a running instance of an Async<'T>, represented as a Task<'T> + /// Starts the `Async<'T>` computation, returning the associated `Task<'T>` val inline toTask: async: Async<'T> -> Task<'T> /// Convert an Async<'T> into an Async, ignoring the result