Task Groups
It should be possible to have a single TaskGroup<Success, Failure: Error> type for throwing and non-throwing subtasks — if the group doesn't conform directly to AsyncSequence, but instead has different values properties for Failure == Error and Failure == Never.
However, to avoid ambiguity you'd still need different top-level with{Throwing}TaskGroup functions, so I'm not sure if this is worth changing. Unless you instead have with... static methods for Failure == Error and Failure == Never.
UPDATE: Should the asyncUnlessCancelled methods have @discardableResults?
Task Priorities
For the platform-independent priorities:
-
.high and .low are fine,
-
.default could be renamed to .medium (to make the relative ordering more obvious),
-
.background might be removed, if it can be implied (e.g. in a daemon background process, or when using the BackgroundTasks framework).
The other aliases will impair auto-completion. Can the Dispatch and Foundation frameworks extend TaskPriority with initializers taking QoS parameters?
Voluntary Suspension
The sleep function accepts a plain integer as nanoseconds to sleep for which mirrors known top-level functions performing the same action in the synchronous world.
Darwin.sleep(_:) has a seconds: CUnsignedInt parameter. Which top-level functions accept a plain integer as nanoseconds?
Task.sleep(_:) would be improved with an argument label, and possibly a different parameter type:
extension Task where Success == Never, Failure == Never {
public static func sleep(forTimeInterval seconds: Double) async
}
This would match the existing Foundation.Thread API, and be compatible with the Foundation.Date APIs. If Double (as an alias for TimeInterval) has 15 significant digits, then it should have nanosecond precision for a range of several days?
Because use-sites look quite explicit in the way they have to prefix this call with an await keyword (await Task.sleep(nanos)), we prefer to use the well-known sleep word rather than introduce new words for this functionality.
Task.yield() could also be renamed. The documentation comments for both APIs are "suspends the current task", so perhaps await Task.suspend() and await Task.suspend(forTimeInterval: seconds).
Can only the current task be suspended, or should it be possible to suspend (and resume) via a task handle?