I think that querying cancellation & local data make sense semantically from the UnsafeContinuation object, at least up until the resume is called. We could treat everything until resume to be part of the task since the task is suspended until then. Task local data would be stable, and cancel are synchronized anyway. After resume, these could just trap.
While I don't see much problem in omitting task local (we can use capture list as others pointed out), we probably need cancellation, since that's the only ever-changing thing that's queried inside a task.
Based on the current structured concurrency pitch, I would expect this to be written as follows, no continuation-specific cancellation functionality needed:
func download(url: URL) async throws -> Data? {
var urlSessionTask: URLSessionTask?
return try Task.withCancellationHandler { urlSessionTask?.cancel() }
operation: {
return try await withUnsafeThrowingContinuation { continuation in
urlSessionTask = URLSession.shared.dataTask(with: url) { data, _, error in
if let error = error {
// Ideally translate NSURLErrorCancelled to CancellationError here
continuation.resume(throwing: error)
} else {
continuation.resume(returning: data)
}
}
urlSessionTask?.resume()
}
}
}
Nothing is being ignored, it has nothing to do with this specific API, so there's no reason to cram in more complexity into it.
Through composition with APIs proposed in structured concurrency, it is able to handle cancelation when necessary, exactly like @jayton suggests (that's one of the ways):
Note that since you're in an async function already (in download), you can normally Task.isCanceled check before submitting any work as well.
Please refer to [Pitch #2] Structured Concurrency - #116 by ktoso for more details on structured concurrency and those APIs; If we made Task a value, then the insides of the continuation can check for it: task.isCanceled as well.
Thanks for this clear answer. Questions are not there to create difficulties, but to get answers to the expected use cases that are not covered in the proposal text.
How about switching checked or unchecked automatically depending on if -Ounchecked (or maybe -O) flag is on? It seems consistent with precondition (or assert).
I don't think we can do that automatically because the types are not layout-compatible; CheckedContinuation needs to hold on to a class instance whose lifetime tracks whether the continuation is leaked, whereas UnsafeContinuation can be implemented as a raw pointer to the task structure.