Skip to content

TaskEx: Async.startImmediateAsTask #142

Closed as duplicate
Closed as duplicate

Description

@bartelink

Replaces #129. TaskShims top level issue: #139

In contrast to its sibling, Async.StartAsTask (because it is not starting a thread), Async.StartImmediateAsTask does not have a taskCreationOptions optional parameter, so people often use it pipeline expressions.

However, that makes it easy to gloss over the fact that the computation will then not have an ambient cancellation token (and be tied to DefaultCancellationToken).

In order to resolve those forces (wanting to be able to execute an async via piping, without the risk of omitting to consider cancelation), it is proposed to have a common helper function (with a lower case name) that

  • takes a cancellation token (as its first argument)
  • passes that and the Async onto Async.StartImmediateAsTask

Current proposed APIs (will be updated inline based on any discussion below):

module Async =
    let inline startImmediateAsTask ct (a : Async<'t>) = Async.StartImmediateAsTask(a, cancellationToken = ct)
   // ALTERNATELY
    let inline executeAsTask ct (a : Async<'t>) = Async.StartImmediateAsTask(a, cancellationToken = ct)

NOTES:

Activity

  1. changed the title [-]TaskShims: Async.startImmediateAsTask[/-] [+]TaskEx: Async.startImmediateAsTask[/+] on Jan 10, 2023
  2. added
    feature requestNew feature or enhancement request
    topic: task-exRelated to the proposed new TaskEx library, which should get its own oss haven
    on Oct 29, 2023
  3. added this to the vFuture milestone on Mar 18, 2024
  4. github-actions commented on Mar 10, 2026

    @github-actions
    Contributor

    🤖 This is an automated response from Repo Assist.

    Thanks for the detailed proposal, @bartelink! A few observations after reviewing the current codebase:

    Current state

    The library currently has AsyncExtensions (adds for x in taskSeq support inside async {}) and TaskExtensions (same for task {}), but no general TaskEx/Async-shim module yet. Issue #139 tracks that top-level effort.

    On the proposed API

    The core proposal is essentially a one-liner:

    module Async =
        let inline startImmediateAsTask ct (a: Async<'t>) =
            Async.StartImmediateAsTask(a, cancellationToken = ct)

    The value it adds is real: forcing the cancellation token to be an explicit positional argument makes it impossible to omit by accident (unlike the optional ?cancellationToken parameter on Async.StartImmediateAsTask itself). The ct-first, async-second ordering also enables clean pipelining.

    Naming

    Between startImmediateAsTask and executeAsTask:

    • startImmediateAsTask mirrors the BCL name, which aids discoverability.
    • executeAsTask is more concise but obscures the "runs on the current synchronisation context" semantics.

    My lean is toward startImmediateAsTask for consistency with F# Core naming conventions.

    Relationship to #141

    Issue #141 (and the open PR #321) addresses the complementary direction — Async.ofTask / awaitTaskCorrect — properly unwrapping AggregateException when bridging Task → Async. Together, Async.ofTask and Async.startImmediateAsTask form a tidy bidirectional bridge.

    Implementation readiness

    This is straightforward to implement. It would fit naturally alongside whatever comes out of #139/#141 as a small TaskEx or Async-extension module. The main open question is whether this belongs in this library at all (vs. a standalone shim package), but given #139 is already tracking broader TaskEx additions, this seems in scope.

    Generated by Repo Assist · ◷

    To install this agentic workflow, run

    gh aw add githubnext/agentics/workflows/repo-assist.md@346204513ecfa08b81566450d7d599556807389f
    
  5. bartelink commented on Mar 18, 2026

    @bartelink
    MemberAuthor

    @T-Gro this issue straddles the first two concerns in our context setting to/fro:

    1. startImmediateAsTask with only a casing difference would be a bad idea (especially as there is a subtle parameter re-ordering involved)
    2. but it does put cancellation front and center which aligns with that principle.

    So, where would you fall on this one?

    1. Can't/shouldn't do, even though it removes a pitfall and ugliness from a relatively common ask, it's not interesting enough for FSharp.Core, and having a PascalCase and a camelCase version of the same thing just makes things confusing
    2. But if we use some other name like executeAsTask, it is toolable and has clear semantics. The naming and semantics should align with Add Async.RunImmediate fsharp/fslang-suggestions#1042
    3. something else?

    As with the general observation that doing Async.Await will likely establish useful precedents for Task.ignore and friends, perhaps Task.ignore can inform the decision process here?

  6. bartelink commented on May 9, 2026

    @bartelink
    MemberAuthor

    Closing as a pipeline friendly function that forces a CancellationToken to be supplied is included in fsharp/fslang-suggestions#1467 (Task.runAsync Task.startAsyncImmediate)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature requestNew feature or enhancement requesttopic: task-exRelated to the proposed new TaskEx library, which should get its own oss haven

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions