Skip to content

Conversation

@abelbraaksma
Copy link
Member

@abelbraaksma abelbraaksma commented Nov 27, 2022

Fixes #43.
Fixes #110.

This basically allows:

let t = task { return 10 } :> Task  // ignore by casting to Task
let ts = taskSeq { do! t } // currently not supported, must be Task<unit>
let ts = taskSeq { do! Task.Delay 10 } // currently not supported

On top of that, this PR will add support for all of ^TaskLike that F#'s task also supports. This change is necessary, as the above distinction isn't possible by adding an overload for the non-generic Task and ValueTask, for the simple reason that Task<'T> :> Task.

The solution chosen in F# was to have a Bind implementation that takes an SRTP parameter of ^TaskLike, which has a GetAwaiter() -> 'T when 'T :> ICriticalNotifyCompletion, as follows:

member inline _.Bind< ^TaskLike, 'TResult1, 'TResult2, ^Awaiter, 'TOverall
    when ^TaskLike: (member GetAwaiter: unit -> ^Awaiter)
    and ^Awaiter :> ICriticalNotifyCompletion
    and ^Awaiter: (member get_IsCompleted: unit -> bool)
    and ^Awaiter: (member GetResult: unit -> 'TResult1)

    ... resumable code implementation ...

Because Task<'T> does have a GetAwaiter on the type, but also inherits Task which in turn implements the non-generic TaskAwaiter, a conflict arises causing an "ambiguous overload" error with just the code above. To solve this, a high-priority overload Bind for Task<'T> is added, which specifically pick the Task<'T>.GetAwaiter: unit -> TaskAwaiter<'T>, as opposed to (Task<'T> :> Task).GetAwaiter: unit -> unit.

Note that the non-generic Task only has the non-generic GetResult: unit -> unit, which fits the above signature where 'TResult1 becomes unit, and no ambiguity arises.

In other words, TaskLike are: ValueTask, ValueTask<'T>, Task. Not TaskLike per the above definition is Task<'T>, which has its own overload.

@abelbraaksma abelbraaksma force-pushed the allow-dobang-with-non-generic-task branch from 46b3dd5 to 9985de0 Compare November 27, 2022 03:45
@abelbraaksma abelbraaksma force-pushed the allow-dobang-with-non-generic-task branch from 0749147 to 88f018e Compare November 27, 2022 16:25
@abelbraaksma abelbraaksma changed the title Implement support for non-generic Task and ValueTask with do! Support all ^TaskLike in do! and let! similar to F#'s task, this includes non-generic Task and ValueTask with do! Nov 27, 2022
@abelbraaksma abelbraaksma merged commit 568f754 into main Nov 27, 2022
@abelbraaksma abelbraaksma deleted the allow-dobang-with-non-generic-task branch November 27, 2022 16:57
@abelbraaksma
Copy link
Member Author

This PR will be part of v0.3.0.

@abelbraaksma abelbraaksma self-assigned this Nov 27, 2022
@abelbraaksma abelbraaksma added enhancement New feature or request topic: ce extensions Extensions to other CE's like task or async topic: taskseq-ce Related to the taskseq computation expression builders or overloads and removed topic: ce extensions Extensions to other CE's like task or async labels Nov 27, 2022
abelbraaksma added a commit that referenced this pull request Nov 27, 2022
@abelbraaksma abelbraaksma added this to the v0.3.0 milestone Mar 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request topic: taskseq-ce Related to the taskseq computation expression builders or overloads

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement ^TaskLike similar to F#'s task Allow use of Task, as opposed to Task<'T> in do! statements

2 participants