In Swift, unlike e.g. C#, it’s not the task itself that’s awaited. I’m pretty sure this would have to be await Task { … }.value
.
Ignoring the missing .value
this does work and is the current way to have an enforced clean-up, but we have to resort to unstructured Concurrency which indicates that we are lacking a feature here. We ought to be able to express everything with structured Concurrency so that the compiler can reason about this.
Having a defer
where we can opt-out of cancellation would be great.
Fun gotcha: In my experience, Task.sleep(nanoseconds:)
returns immediately if you do that. Sleeping the current task next-to-forever seems to work with .max / 2
nanoseconds however. Maybe it's internally reinterpreting the UInt64
as signed?
(Also you probably mean to try? await
that so it handles and ignores CancellationError
.)
This would check out: setting only the MSb (i.e. (.max >> 1) + 1
or ~UInt64(Int64.max)
) returns just as immediately. That should either be fixed or documented.
The source of that bug is described here: Fix bug in Dispatch executor preventing long sleeps by rauhul · Pull Request #64304 · apple/swift · GitHub but I haven't found the time to follow up on my patch.
It doesn't look like someone can take the helm on implementing async defer
, so in the meantime I have changed all these occasions to spawning a task and waiting for it w/ semaphores. Ugly, but does the job.
I, too, would like this, and I'd like to also throw out of defer:
try await defer { try await something() }
+1 for a try-able await-able defer.
I really value the straight-line code where the deallocation is shown next to the allocation that the defer mechanism promotes. It's unfortunate that if the method (e.g. close()) is fallible and/or async that you can't use the defer mechanism at all.
Hm, isn't try in a defer a bit weird? What if the function already threw and then throws again in the defer? Would it take the first error thrown or the last? I think there was probably a good reason why trying in defer was not introduced in the first place.
I think that this case can be handled in a variety of ways. For example, here is what Go does for panics (their version of throwable errors) during defer execution, which is to wrap them all up.